最简路由转发应先用 net/http 原生能力硬编码转发,避免过早引入中间件或高级路由库;必须显式透传 host 头、自定义 transport 和 errorhandler,并手动安全重写路径;健康检查与熔断需按上游服务单独实现。

用 net/http 做最简路由转发,别一上来就写中间件链
Go 写 API 网关,最容易掉进“架构幻觉”:还没跑通一个请求,就在设计插件系统、配置热加载、JWT 解析中间件。实际第一步只是让 http.ServeMux 或 http.HandlerFunc 把请求原样转给后端服务。
- 先硬编码一个
http.Post或http.DefaultTransport.RoundTrip调用目标服务,确认能通;不要碰gorilla/mux或gin—— 它们自带路由语义,会模糊你对“转发”本质的理解 - 注意 Host 头必须显式透传:
req.Host = upstreamHost,否则 Nginx 或云厂商 LB 可能 404 - 别用
httputil.NewSingleHostReverseProxy开局——它默认不透传X-Forwarded-For,也不处理 Upgrade header(WebSocket 就断)
httputil.NewSingleHostReverseProxy 的三个必改字段
这个函数看着省事,但开箱即用会出生产事故。它只改了 Director,其余关键行为全靠默认值扛,而默认值在网关场景下基本都不对。
-
Director里必须重设req.URL.Scheme和req.URL.Host,否则 HTTPS 后端收到 HTTP URL 会 301 跳转 -
Transport必须自定义:默认的http.DefaultTransport没设MaxIdleConnsPerHost,长连接池会耗尽,表现为间歇性超时 -
ErrorHandler必须重写:默认直接 write string 错误,前端收不到标准 JSON error body,前端工程师会半夜打电话
示例关键片段:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
proxy := httputil.NewSingleHostReverseProxy(upstreamURL)
proxy.Transport = &http.Transport{
MaxIdleConnsPerHost: 100,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
proxy.ErrorHandler = func(rw http.ResponseWriter, req *http.Request, err error) {
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(http.StatusBadGateway)
json.NewEncoder(rw).Encode(map[string]string{"error": "upstream failed"})
}
路径重写用 req.URL.Path 手动切,别信正则替换库
网关常要 /api/v1/users → /users,看似简单,但 strings.Replace 或第三方 path rewrite 库会在边界 case 翻车:比如 /api/v1/user → /user,结果把 /api/v1/user-profile 也错改成 /user-profile。
- 只用
strings.HasPrefix(req.URL.Path, prefix)+strings.TrimPrefix,严格前缀匹配 - 重写后记得同步处理
req.URL.RawPath(如果存在),否则带中文或特殊字符的路径会 decode 失败 - 别在
Director外做路径操作——Director是唯一安全时机,此时req.URL还没被 transport 读取
健康检查和熔断得自己写,gobreaker 不适合网关粒度
网关的下游是多个异构服务,每个服务的失败模式不同:有的慢,有的 503 频发,有的偶发 timeout。用通用熔断器(如 gobreaker)套在所有 upstream 上,会导致一个弱服务拖垮整个网关流量。
- 为每个 upstream 单独维护计数器:每秒请求数、错误率、P99 延迟,用
sync.Map存,key 是 upstream host - 健康检查走独立 goroutine +
http.Head,间隔 5 秒,超时 1 秒,连续 3 次失败才标记 down - 转发前查状态:若 upstream 标记为 down,直接返回 503,不发请求——这点比熔断逻辑本身更重要
真正难的不是代码,是判断什么时候该把一个上游从 “slow but alive” 切到 “down and skip”。这得看业务 SLA,没法交给库自动决定。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










