最简路径是使用 httputil.newsinglehostreverseproxy(url.parse("http://backend:8080")),需确保 url 含协议和主机,避免相对路径,并自定义 director 修改请求头与路径、配置 transport 超时与连接池。

用 net/http/httputil 新建反向代理实例最简路径
Go 标准库的 httputil.NewSingleHostReverseProxy 是开箱即用的起点,别自己重写转发逻辑。它自动处理请求头、URL 重写、后端连接复用等细节,但前提是传入的 *url.URL 必须带协议和主机,不能是相对路径。
-
http://backend:8080✅ 可用;/api❌ 会 panic 报parse "/api": missing protocol scheme - 后端地址建议用变量控制,避免硬编码:
backendURL, _ := url.Parse("http://localhost:3000") - 如果后端是 HTTPS,注意 Go 默认不校验证书,测试时可临时加
Transport跳过验证(上线必须删)
修改请求头和路径前缀时绕开 Director 的常见误操作
很多人直接改 req.Host 或拼接 req.URL.Path,结果出现重复路径、丢失查询参数或 Host 被覆盖。真正该动的是代理的 Director 函数——它在每次转发前被调用,是唯一安全修改请求的地方。
- 必须显式设置
req.URL.Scheme = backendURL.Scheme和req.URL.Host = backendURL.Host,否则默认沿用客户端请求的 scheme/host - 路径重写要小心:用
strings.TrimPrefix(req.URL.Path, "/prefix"),而不是req.URL.Path = "/new" + req.URL.Path,后者会破坏原始路径结构 - 别漏掉
req.Header.Set("X-Forwarded-For", clientIP),否则后端拿不到真实 IP(req.RemoteAddr是代理本机地址)
处理超时和连接池需手动配置 Transport
默认的 http.DefaultTransport 对反向代理不友好:没有超时控制,空闲连接不回收,容易耗尽文件描述符。必须新建 http.Transport 并挂到代理的 Transport 字段上。
- 关键三超时必须设:
Timeout(总超时)、IdleConnTimeout(空闲连接存活时间)、TLSHandshakeTimeout(TLS 握手上限) -
MaxIdleConns和MaxIdleConnsPerHost建议设为 100 左右,太小导致频繁建连,太大压垮后端 - 示例片段:
proxy.Transport = &http.Transport{IdleConnTimeout: 30 * time.Second, ...}
调试 502/504 错误时优先检查后端健康状态和日志输出
反向代理本身极少抛错,502 Bad Gateway 几乎都源于后端不可达或返回非法响应;504 Gateway Timeout 则是 Transport 超时或后端响应太慢。别急着改代理代码。
立即学习“go语言免费学习笔记(深入)”;
- 先用
curl -v http://localhost:8080直连后端,确认能通且返回 HTTP/1.1 状态行 - 代理启动时加日志:在
Director里打log.Printf("proxying to %s", req.URL),确认路径和 host 是否符合预期 - 若后端是本地服务,检查是否绑定
127.0.0.1而非localhost(Go 解析localhost可能走 IPv6,导致连不上)
代理逻辑本身很薄,大部分问题出在 URL 构造、Transport 配置、后端响应格式这三处。改完记得重启进程——Go 二进制没热重载,改了配置不重启等于白改。










