在现代 Web 架构中,Nginx 几乎是无处不在的“全能瑞士军刀”。它不仅能作为高性能的 Web 服务器,更常扮演着反向代理API 网关的关键角色。而在配置反向代理时,有一个场景我们几乎都会遇到,那就是——URL 路径重写,或者说,去除请求路径中的特定前缀

看似一个小小的配置,背后却隐藏着 Nginx 最核心的代理逻辑。配置对了,请求丝滑转发;配置错了,后端服务收到一堆 404,让你抓耳挠腮。

今天,我们就把这个知识点彻底讲透,让你彻底掌握 Nginx 路径重写的艺术。

一、为什么需要去除前缀?场景还原

想象一下,我们正在构建一个微服务系统。系统有一个统一的入口(API 网关),域名是 https://example.com。后面则部署了多个独立的微服务,比如:

  • 用户服务 (User Service):监听在 http://localhost:8001
  • 订单服务 (Order Service):监听在 http://localhost:8002

这些微服务自身是不知道自己被代理的。例如,“用户服务”提供的接口是 /users/123,而不是 /api/user/users/123

为了方便管理和区分,我们希望 API 网关的 URL 结构是这样的:

  • 所有访问用户服务的请求,都以 /api/user/ 开头。
  • 所有访问订单服务的请求,都以 /api/order/ 开头。

我们的核心目标是

当用户访问 https://example.com/api/user/users/123 时,Nginx 需要将请求转发给 http://localhost:8001,并且转发到后端的路径应该是 /users/123,而不是原始的 /api/user/users/123

这个**“剪掉” /api/user/** 的过程,就是我们所说的“去除前缀”。

图1: Nginx 去除前缀的反向代理流程

graph TD A[用户] -->|GET /api/user/users/123| B(Nginx 网关); B -->|proxy_pass http://.../| C{路径重写<br/>去除 /api/user/}; C -->|GET /users/123| D[后端用户服务];

二、核心知识点:proxy_pass 指令的“斜杠魔法”

要实现这个功能,关键在于 proxy_pass 指令后面 URL 的写法,特别是末尾是否带有斜杠 (/)。这是 Nginx 路径重写中最核心、最关键的区别!

我们直接看规则:

  1. proxy_pass 目标 URL 不带斜杠 (/)

    • 行为:Nginx 会将 location 匹配到的完整 URI 直接拼接到目标 URL 后面。
    • 结果:不去除前缀。
  2. proxy_pass 目标 URL 带有斜杠 (/)

    • 行为:Nginx 会将 location 匹配到的那部分前缀路径剥离,然后将剩余部分拼接到目标 URL 后面。
    • 结果:成功去除前缀!

听起来有点绕?我们用上面的“用户服务”场景来举例说明。

错误的配置(不去除前缀)

server {
    location /api/user/ {
        # 注意!目标URL末尾没有 "/"
        proxy_pass http://localhost:8001; 
    }
}
  • 请求: GET /api/user/users/123
  • 后端收到的请求: GET /api/user/users/123 <-- 错误!

正确的配置(成功去除前缀)

server {
    location /api/user/ {
        # 注意!目标URL末尾有一个神奇的 "/"
        proxy_pass http://localhost:8001/; 
        
        # 顺便加上推荐的代理头信息
        proxy_set_header Host $host;
        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;
    }
}
  • 请求: GET /api/user/users/123
  • 后端收到的请求: GET /users/123 <-- 正确!

总结一下: proxy_pass 后面有没有斜杠,是两种完全不同的代理行为。想要去除 location 匹配的前缀,就一定要在 proxy_pass 的 URL 末尾加上 /

三、更强大的武器:rewrite 指令

虽然“斜杠魔法”能解决大部分问题,但有时我们需要更精细、更复杂的路径重写规则。这时候,rewrite 指令就该登场了。

server {
    location /api/user/ {
        # 1. 使用rewrite重写URI
        rewrite ^/api/user/(.*)$ /$1 break;
        
        # 2. 将重写后的URI代理到后端
        proxy_pass http://localhost:8001;
    }
}

rewrite 的优势在于灵活性可读性,可以实现非常复杂的匹配和替换逻辑。

四、一个常见的陷阱:后端重定向问题

配置好代理后,还有一个常见的问题需要注意。如果后端服务返回一个相对路径的重定向 (Location: /login),浏览器会错误地跳转到 https://example.com/login,导致404。

图2: 错误的重定向流程 vs 正确的重定向流程

sequenceDiagram participant B as Browser participant N as Nginx participant S as Backend rect rgb(255, 200, 200) Note over B,S: 错误流程 (无 proxy_redirect) B->>N: GET /api/user/dashboard N->>S: GET /dashboard S-->>N: 302 Location: /login N-->>B: 302 Location: /login B->>N: GET /login N-->>B: 404 Not Found end rect rgb(200, 255, 200) Note over B,S: 正确流程 (使用 proxy_redirect) B->>N: GET /api/user/dashboard N->>S: GET /dashboard S-->>N: 302 Location: /login Note right of N: proxy_redirect 修改头为 /api/user/login N-->>B: 302 Location: /api/user/login B->>N: GET /api/user/login N-->>B: 200 OK end

解决方案:proxy_redirect 指令
proxy_redirect 指令专门用于修改后端返回的 Location 响应头。

location /api/user/ {
    proxy_pass http://localhost:8001/;
    
    # 智能修复重定向路径
    # 当后端返回 "Location: /" 时, Nginx自动修改为 "Location: /api/user/"
    proxy_redirect / /api/user/;
    
    # ... 其他 proxy_set_header ...
}

proxy_redirect default; 也能在很多情况下智能地处理,但显式声明是是更稳妥的做法。

总结与探讨

让我们快速回顾一下今天的核心知识点:

  1. 最简单的方法:在 proxy_pass 的目标 URL 末尾添加斜杠 /,即可自动去除 location 匹配到的路径前缀。
  2. 更强大的方法:使用 rewrite ... break; 指令,通过正则表达式精确重写 URI。
  3. 别忘了陷阱:使用 proxy_redirect 指令来修正后端服务返回的相对路径重定向。

掌握了这三点,您就可以自信地应对 Nginx 中几乎所有的反向代理路径重写需求了。


👇 欢迎在评论区留下你的看法 👇

到你了!关于 Nginx 路径重写,我们想听听你的声音:

  1. 你是“斜杠派”还是“rewrite 派”? 在日常工作中,你更倾向于使用哪种方式来处理路径?
  2. 分享你的“坑”! 在配置 Nginx 代理时,你还遇到过哪些令人印象深刻的“坑”或者有趣的技巧?
  3. 还有什么想学的? 关于 Nginx,你最想了解哪个主题(比如:负载均衡、缓存、高可用)?

期待你的留言,让我们在交流中共同进步!如果你觉得文章有用,别忘了点赞、在看、分享三连支持一下!

Q.E.D.


寻门而入,破门而出