director函数必须重写,否则90%请求出问题;需显式设置req.url.scheme、req.url.host、req.host,透传x-forwarded-for/upgrade/connection头,并配置transport超时与连接池。

直接用 httputil.NewSingleHostReverseProxy 启动代理,不改 Director 函数,90% 的请求会出问题:头被删、路径错乱、WebSocket 断连、超时无响应——这不是配置漏了,是 Go 默认行为就按“安全代理链”设计的,而你实际要的是“透明转发”。
Director 函数必须重写,否则后端收不到正确 Host 和路径
默认 Director 只改了 req.URL.Host,但保留原始 req.URL.Path 和 req.Host。后端服务常依赖 Host 头做多租户路由,或靠 Path 匹配内部接口。
- 必须显式设置
req.URL.Scheme = u.Scheme和req.URL.Host = u.Host,否则后端看到的仍是客户端发来的 Host(比如api.example.com),而非你期望的backend:8080 - 路径前缀剥离要用
path.Clean+strings.TrimPrefix,例如网关挂载在/api,后端期望/users,就得写:req.URL.Path = strings.TrimPrefix(path.Clean(req.URL.Path), "/api"),再补上开头的/ - 别漏掉
req.URL.RawQuery = req.URL.RawQuery,否则查询参数(?id=123)会丢失
请求头不是“自动透传”,X-Forwarded-* 和 Upgrade 都得手动加
ReverseProxy 内部对请求头做了白名单过滤,Connection、Upgrade、X-Forwarded-For 等关键头默认被删——这是为防止代理污染,但业务场景下你恰恰需要它们。
- 真实客户端 IP 必须靠
req.Header.Set("X-Forwarded-For", req.RemoteAddr)补,req.RemoteAddr是代理本机地址,不是用户 IP;若前端有可信 LB,应从X-Real-IP或X-Forwarded-For中取最左非私有 IP - WebSocket 必须透传
Upgrade和Connection头:req.Header.Set("Upgrade", req.Header.Get("Upgrade"))、req.Header.Set("Connection", req.Header.Get("Connection")) - HTTPS 透传需补
X-Forwarded-Proto: https,否则后端生成跳转链接可能变成http://
Transport 不配超时和连接池,高并发下会卡死或 504
默认 http.DefaultTransport 没设超时,空闲连接永不释放,文件描述符很快耗尽,表现就是请求堆积、504 Gateway Timeout 频发。
- 必须新建
http.Transport并赋给proxy.Transport,至少设三个超时:Timeout(总超时)、IdleConnTimeout(空闲连接存活时间)、TLSHandshakeTimeout -
MaxIdleConns和MaxIdleConnsPerHost建议设为100左右,太小导致频繁建连,太大压垮后端 - 测试环境若用 HTTPS 后端且证书不可信,可临时设
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},上线前必须删掉
502/504 错误别急着改代理代码,先确认后端是否真健康
ReverseProxy 本身极少抛错,95% 的 502 Bad Gateway 是后端挂了或返回了非法响应(比如空 body + 200),504 Gateway Timeout 则基本等于 Transport 超时或后端响应太慢。
- 调试时先绕过代理,用
curl -v http://backend:8080/health直连后端,确认能通、响应格式合法 - 日志里捕获
context.Canceled错误,这通常是客户端主动断连(比如浏览器关闭页面),不是代理 bug - 如果用了自定义
ErrorHandler,注意它只捕获 Transport 层错误,不处理后端返回的 4xx/5xx 响应——那些得靠ModifyResponse拦截
最易被忽略的一点:所有对 req.Header 和 req.URL 的修改,都必须在 Director 函数里做,且不能有阻塞操作;一旦漏掉某一个头、某一次路径修正,问题往往延迟暴露,比如只在特定路径、特定协议(HTTPS/WebSocket)下才复现。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











