本文由AI润色。
在配置 Nginx 反向代理时,经常能看到以下两种写法:
| |
末尾仅差一个 /,但转发到上游服务的实际路径截然不同。其核心差异在于 Nginx 处理 proxy_pass 时是否包含了 URI,进而决定了路径是“原样透传”还是“前缀替换”。
0.总览

1. location 中的 /:请求匹配范围
location 用于定义请求 URL 的路由匹配规则。常见的前缀匹配行为如下:
location /:作为兜底匹配,捕获所有以/开头的请求。location /api/:严格匹配以/api/为前缀的请求路径。
| 请求路径 | location /api/ 是否匹配 | 说明 |
|---|---|---|
/api/user | 匹配 | 以前缀 /api/ 开头 |
/api/order/123 | 匹配 | 以前缀 /api/ 开头 |
/api/ | 匹配 | 精确匹配该目录 |
/api | 特殊处理 | 默认不匹配,但见下方说明 |
/api123 | 不匹配 | 不属于 /api/ 路径 |
/user | 不匹配 | 前缀不同 |
/api 与 /api/ 的关键区别:
location /api是纯字符串前缀匹配,不仅能命中/api/user,还会误伤/api123。location /api/限定了目录层级,不会匹配/api123。
因此在代理整个接口前缀时,推荐显式指定尾部斜杠 location /api/。
注: 当
location /api/内部包含proxy_pass指令时,如果客户端直接请求/api,Nginx 内部会触发隐式优化,自动返回 301 重定向到/api/。
2. proxy_pass 中的 /:路径透传与截断替换
Nginx 官方文档规定:如果 proxy_pass 指令中带有了 URI(哪怕只是一个 /),请求中与 location 匹配的部分就会被替换为指令中的 URI;如果未携带 URI,则保留原请求完整路径透传。
场景一:未指定 URI(完整保留原路径)
| |
客户端访问 [http://example.com/api/user](http://example.com/api/user) 时:
proxy_pass 只有 host:port,没有指定任何路径。Nginx 会将原始路径直接拼接到后端地址之后:
[http://127.0.0.1:8080/api/user](http://127.0.0.1:8080/api/user)(原始 /api/ 得到保留)。
场景二:显式指定 URI 为 /(截断前缀)
| |
客户端同样访问 [http://example.com/api/user](http://example.com/api/user) 时:
proxy_pass 指定了 URI 为 /,Nginx 执行字符串替换:
| |
后端最终接收到的请求为:[http://127.0.0.1:8080/user](http://127.0.0.1:8080/user)。
3. proxy_pass 指定自定义 URI(路径重写)
替换逻辑并不局限于删除前缀,如果 proxy_pass 中指定了其他子路径,Nginx 会完成前缀映射:
| |
当客户端请求 /api/user 时,计算流程如下:
| |
计算逻辑可抽象为:
$$\text{转发路径} = \text{proxy_pass 指定的 URI} + (\text{原始请求路径} - \text{location 匹配的前缀})$$

4. 常见配置组合与“双斜杠”问题
假设客户端统一请求 [http://example.com/api/user](http://example.com/api/user):
| location 配置 | proxy_pass 配置 | 转发给后端的路径 | 说明 |
|---|---|---|---|
/ | http://backend | /api/user | 不带 URI,全量透传 |
/ | http://backend/ | /api/user | 匹配 /,替换为 /,结果等同透传 |
/ | http://backend/v1/ | /v1/api/user | 匹配 /,替换为 /v1/ |
/api/ | http://backend | /api/user | 不带 URI,全量透传 |
/api/ | http://backend/ | /user | 带 URI /,剥离 /api/ 前缀 |
/api/ | http://backend/v1/ | /v1/user | 替换 /api/ 为 /v1/ |
/api | http://backend | /api/user | 不带 URI,全量透传 |
/api | http://backend/ | //user | 产生双斜杠(见下文分析) |
/api | http://backend/v1 | /v1/user | 匹配 /api,替换为 /v1,拼接余下的 /user |
/api | http://backend/v1/ | /v1//user | 产生双斜杠 |
双斜杠 // 产生的原因
当配置如下时:
| |
客户端访问 /api/user:
location /api仅匹配了/api这 4 个字符。- 剥离匹配部分后,剩余路径为
/user。 proxy_pass指定的前缀为/。- 拼接结果:
/+/user=//user。
虽然大部分 Web 框架与后端路由解析器具备路径归一化(Normalize)能力,会自动合并多余斜杠,但在 Nginx 层面应保持前缀规范,遵循“location 末尾带斜杠,proxy_pass 相应带斜杠”的书写习惯。
5. Query 参数处理
Query 参数(即 URL ? 后的键值对)不受前缀替换影响,始终会被自动原样附带到最终请求后。
| |
访问 /api/user?id=123&name=tom 时,后端直接收到 /backend/user?id=123&name=tom。
6. 生产配置选型实践
根据后端接口设计,选用对应配置模板:
方案 A:后端接口天然自带 /api/ 前缀
后端服务的路由定义本身就是 /api/user,此时网关只需透传:
| |
方案 B:后端为独立服务,内部路径无 /api/
外部统一通过 /api/ 路由隔离,但内部服务实际路由为 /user:
| |
方案 C:前后端路由映射前缀不同
需要将外部 /api/ 统一映射到内部各微服务的 /internal/ 前缀:
| |
7. 边界与限制
上述截断替换机制仅在普通前缀匹配 location中生效。以下场景行为不同:
- 正则 location 中禁止在 proxy_pass 中定义 URI:
在
location ~ ^/api/这类正则块中,proxy_pass只能写到ip:port(或 upstream 名),不能包含子路径(如http://backend/会报错nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression)。若需要改写路径,必须在块内搭配rewrite ... break;指令。 - rewrite 指令接管:
如果在普通 location 中显式调用了
rewrite ... break;,请求的 URI 已在 Nginx 内部完成了变更,proxy_pass后续将直接转发改写后的路径,不再执行常规的前缀替换逻辑。




