最简反向代理骨架需用httputil.newsinglehostreverseproxy并正确配置director函数,手动设置req.url.scheme、req.url.host和host头,补全x-forwarded-for,自定义transport设超时,避免director中耗时操作。

用 httputil.ReverseProxy 搭建最简反向代理骨架
直接复用 Go 标准库的 httputil.ReverseProxy 是最快启动微网关的方式,它不依赖任何第三方框架,内存占用低、无额外抽象层,适合边缘或资源受限场景。
常见错误是忽略 Director 函数里对 req.URL 的重写——漏掉这步会导致后端收到的 Host 和 Path 错乱,返回 404 或 502。必须手动设置 req.URL.Scheme、req.URL.Host 和 req.Header 中的 Host 字段。
- 转发前务必调用
req.Header.Set("X-Forwarded-For", clientIP),否则下游服务拿不到真实客户端 IP - 若后端是 HTTPS,需显式设置
url.Scheme = "https"并配置http.Transport.TLSClientConfig,否则会报x509: certificate signed by unknown authority - 不要在
Director里做耗时操作(如 DB 查询或 HTTP 调用),它运行在主请求 goroutine 中,会阻塞整个代理流程
用 context.WithTimeout 控制单次转发生命周期
高并发下,一个慢后端可能拖垮整个网关。标准 ReverseProxy 默认无超时,必须通过自定义 http.Transport 注入上下文超时逻辑。
关键点在于:超时必须设在 transport 层(连接、读写),而非 handler 层——后者只控制 handler 函数执行时间,无法中断底层 TCP 连接或阻塞的 read/write 系统调用。
-
transport.ResponseHeaderTimeout控制从后端收到响应头的时间,建议设为2s~5s -
transport.DialContext需包装为带 timeout 的 dialer,避免 DNS 解析或 TCP 握手无限等待 - 别用
time.AfterFunc手动 cancel,直接用context.WithTimeout(req.Context(), ...)传递给 transport 即可,Go 运行时自动处理取消信号
用带缓冲 channel 实现轻量级限流器
不需要引入 golang.org/x/time/rate 这类重量级限流器。在 QPS 不超过 5k 的中小规模网关中,一个固定大小的 chan struct{} 就足够应对突发流量,且零 GC 开销。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
典型误用是把 channel 放在全局变量里却没做并发保护——多个 goroutine 同时往未加锁的 channel 写会导致 panic: send on closed channel。
- 声明为
var limiter = make(chan struct{}, 100),数字即最大并发请求数 - 每个请求进来先执行
select { case - 务必在 defer 中执行
limiter ,确保无论成功失败都释放令牌 - 注意:该方式是“连接级”限流,不是“请求速率”限流;若需 per-IP 或 per-token 限流,必须配合 map + sync.RWMutex
避免 goroutine 泄露导致 CLOSE-WAIT 积压
网关长期运行后出现大量 CLOSE-WAIT 连接,八成是因为未正确关闭后端连接或未消费 response body。Go 的 http.Transport 会复用连接,但前提是上层代码主动读完 resp.Body。
最隐蔽的坑是:你用了 proxy.ServeHTTP,但没意识到它内部调用 resp.Body.Close() 的时机依赖于你是否已读取全部 body 数据。如果中间件提前 return,body 就可能没被读完。
- 务必在自定义 middleware 中用
io.Copy(io.Discard, resp.Body)显式丢弃未读 body - 不要在
Director或 middleware 中启动新 goroutine 处理 request/response,除非你能保证它一定结束并 close 所有打开的 reader/writer - 用
netstat -an | grep CLOSE-WAIT | wc -l定期检查,超过 200 就要排查连接释放路径
实际部署时,最易被忽略的是 transport 的 idle connection 复用配置。默认 MaxIdleConnsPerHost = 2,在多后端实例场景下极易成为瓶颈。至少设为 100,并配 IdleConnTimeout = 30 * time.Second,否则连接池会频繁新建/销毁 TCP 连接。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










