直接用 httputil.newsinglehostreverseproxy 会出 404、502、超时或丢头,因默认 director 仅改路径和查询参数,未重写 req.url.scheme 和 req.url.host,导致后端路由失败、连接被拒;须在 director 中显式设置 scheme/host、补 x-forwarded-for 等头、自定义 transport 并配置超时与连接池。

直接用 httputil.NewSingleHostReverseProxy 会出 404、502、超时或丢头,不是代理写错了,是默认行为没对齐后端需求。
Director 必须重写 req.URL.Host 和 req.URL.Scheme
默认 Director 只改了 req.URL.Path 和 req.URL.RawQuery,但保留原始 Host 头和 URL scheme/host —— 后端若靠 Host 路由(如 Nginx 的 server_name、K8s Ingress),就会 404;若后端只监听 127.0.0.1:8080 却收到 localhost:8080,可能因 hosts 或 DNS 缓存被拒绝连接。
- 必须在
Director函数里显式赋值:req.URL.Scheme = u.Scheme、req.URL.Host = u.Host(u是你url.Parse出来的后端地址) - 本地开发优先用
http://127.0.0.1:3000,别用http://localhost:3000,绕开解析不确定性 - 如果后端是 HTTPS,
u.Scheme必须为"https",且 Transport 需处理证书(测试可跳过,上线必须校验)
透传真实客户端 IP 得手动设 X-Forwarded-For
默认 ReverseProxy 不加任何 X-Forwarded-* 头,后端 req.RemoteAddr 永远是 127.0.0.1:xxxx,拿不到真实 IP。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 在
Director里加:req.Header.Set("X-Forwarded-For", clientIP(req)),其中clientIP应优先读req.Header.Get("X-Real-IP"),fallback 到strings.Split(req.RemoteAddr, ":")[0] - 不要无脑追加 —— 若上游已带
X-Forwarded-For,应做拼接:old := req.Header.Get("X-Forwarded-For"); req.Header.Set("X-Forwarded-For", old + ", " + ip) - 别漏
X-Forwarded-Proto:req.Header.Set("X-Forwarded-Proto", "https")(若代理走 HTTPS)
Transport 不配就容易卡死或内存暴涨
默认 http.DefaultTransport 没超时、没连接池限制、不回收空闲连接 —— 后端一慢或挂,请求就堆在连接池里,goroutine 数飙升,文件描述符耗尽,表现就是高并发下延迟陡增或 504。
- 必须新建
http.Transport并赋给proxy.Transport,至少设:IdleConnTimeout: 30 * time.Second、MaxIdleConns: 100、MaxIdleConnsPerHost: 100 - 三个关键超时不能少:
Timeout(总耗时上限)、TLSHandshakeTimeout(避免 TLS 握手卡住)、KeepAlive(TCP keepalive 间隔) - 别复用全局
http.DefaultClient.Transport,每个ReverseProxy实例配独立 transport
转发 WebSocket 要手动透传 Upgrade 和 Connection 头
原生 ReverseProxy 把 Upgrade、Connection 当作 hop-by-hop 头自动删了,导致 WebSocket 升级失败,卡在 101 后断连。
- 在
Director之后、proxy.ServeHTTP之前补头:req.Header.Set("Connection", req.Header.Get("Connection"))、req.Header.Set("Upgrade", req.Header.Get("Upgrade")) - 确保
Transport.DisableKeepAlives == false(默认就是 false,但显式写出来更稳) - 检查中间链路:云厂商 SLB 若只开 HTTP 模式,不支持 WebSocket Upgrade,得切到 TCP/SSL 模式
最易被忽略的点是:所有修改都必须在 Director 函数里做,而不是在 handler 里改 req —— Director 是唯一被 ReverseProxy 调用并保证生效的地方;另外,url.Parse 的输入必须含协议和 host,"http://backend:8080" ✅,"/api" ❌ 会 panic。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










