proxy_pass末尾必须加/,否则路径原样透传导致Gin等框架因未注册/api/前缀而404;Go服务须绑定127.0.0.1,Nginx需透传X-Real-IP等头以获取真实客户端IP。

proxy_pass末尾斜杠不加,Go服务直接404
绝大多数 404 都出在这里:Nginx 的 proxy_pass 指令末尾是否带 /,决定了路径如何拼接。Gin 默认路由从根路径注册(比如 GET /health),不加斜杠会导致请求路径原样透传。
-
location /api/ { proxy_pass http://backend; }→ 请求/api/v1/users被发往后端的/api/v1/users(Gin 没注册该路由,404) -
location /api/ { proxy_pass http://backend/; }→ 请求被重写为/v1/users,匹配 Gin 的GET /v1/users
别依赖“试试看”,所有 proxy_pass 指向 Gin 后端时,结尾必须加 /;如果后端本身带前缀(如 http://svc:8080/api),才考虑不加。
Gin里用httputil.ReverseProxy实现路由级代理
想在 Gin 内部做代理(比如 /legacy/* 转发到旧系统),不能直接用 httputil.NewSingleHostReverseProxy —— 它的 Director 是私有实现,没法控制多目标或路径重写。
- 必须手动构造
&httputil.ReverseProxy{Director: func(req *http.Request) { ... }} - Director 函数里三件事缺一不可:
req.URL.Scheme、req.URL.Host、req.Host全部显式赋值 - 路径重写靠
req.URL.Path = strings.TrimPrefix(req.URL.Path, "/legacy"),否则后端收不到干净路径 - 别在 Director 里做 HTTP 健康检查,它在主请求链路上,会拖慢所有用户响应
upstream后端地址必须绑定127.0.0.1,不能用0.0.0.0
Nginx 的 upstream 块探测健康状态时走的是本地回环路径。Go 服务若监听 0.0.0.0:8081 或只写 :8081,可能响应来自任意网卡的请求,导致 Nginx 探活失败或流量绕过代理。
立即学习“go语言免费学习笔记(深入)”;
- 启动 Go 服务时明确指定地址:
app.Run("127.0.0.1:8081") - Docker 场景下,Nginx 和 Go 不在同一容器时,
upstream改用服务名(如server go-app-1:8081),而非127.0.0.1 - 别省略端口:即使 HTTP 默认 80,也写成
localhost:8081,避免协议歧义
真实客户端IP在Gin里拿不到?Nginx头没透传或Go没读对
默认 c.ClientIP() 返回的是 Nginx 的地址(127.0.0.1),不是用户真实 IP。这问题不解决,日志、限流、风控全失效。
- Nginx 配置必须包含这三行:
proxy_set_header X-Real-IP $remote_addr;、proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;、proxy_set_header X-Forwarded-Proto $scheme; - Gin 中不要直接用
r.RemoteAddr,优先调c.ClientIP()(它已封装解析逻辑);若需原始头,用c.Request.Header.Get("X-Real-IP") -
X-Forwarded-For可能是逗号分隔链(如203.0.113.195, 192.168.1.1),c.ClientIP()默认取第一个,符合多数场景
路径重写、头透传、地址绑定——这三个点漏掉任何一个,代理就只是“能通”,而不是“可用”。尤其 proxy_pass 斜杠和 127.0.0.1 绑定,线上出问题时最常被忽略。


















