最稳路由方式是location前缀匹配:location /api/配proxy_pass http://backend(无斜杠),透传完整uri;带斜杠则剥离前缀,易致502/404;复杂动态路由用顶层map配合default兜底,禁用if;header含下划线需开启underscores_in_headers on。

直接用 location 前缀匹配,最稳;复杂路由逻辑才上 map,别在 location 里写 if —— 那玩意儿不保证执行顺序,容易漏转发、路径错乱、502 报错。
用 location /path/ 做前缀分流最可靠
这是 Nginx 官方推荐、性能最好、行为最确定的方式。只要 URI 有明确层级(比如 /api/、/admin/、/static/),就该优先走这条路。
-
location按最长前缀匹配,不用写正则,启动快、运行快 - 每个
location块里配一个proxy_pass http://upstream_name,地址末尾不带/ - 若
location /api/,且proxy_pass http://api_backend(无斜杠),则/api/v1/user会完整透传为/api/v1/user到后端 - 若误写成
proxy_pass http://api_backend/(带斜杠),请求会变成/v1/user,丢掉/api前缀 —— 这是线上最常见 502 或 404 的根源
用 map 根据 URI 变量做动态路由
当需要按 URI 中的字段(如版本号、区域码、ID 段)做判断时,map 比一堆 if 更安全、更易维护。但它必须定义在 http 块顶层,不能塞进 server 或 location 里。
-
map只支持字符串精确匹配或 PCRE 正则,不自动 trim 空格、不忽略大小写、不解析 URL 编码 ——/user/123%20和/user/123是两个不同值 - 目标变量名必须以
$开头,且不能已被其他指令定义过,比如$backend不能在map外先赋值 - 匹配不到时变量为空,如果
proxy_pass http://$backend引用空值,Nginx 直接返回 502 —— 务必加default分支兜底 - 示例:
map $request_uri $backend { default web_backend; ~^/v2/ api_v2_backend; ~^/v1/ api_v1_backend; }
proxy_pass 后面那个斜杠到底要不要?
这个细节决定路径是否透传,不是风格问题,是行为差异。
-
proxy_pass http://backend→ 原始 URI 完整转发(推荐) -
proxy_pass http://backend/→ 删除匹配到的location路径部分,只转发剩余路径(相当于内部重写) - 特别注意:如果
location /foo(没结尾斜杠),而proxy_pass http://backend/,Nginx 会把/foo/bar变成/bar;但若location /foo/+proxy_pass http://backend/,结果一样 —— 关键看匹配段是否被截掉 - 真正要改写路径(比如统一去掉
/v1前缀),得用rewrite ^/v1/(.*)$ /$1 break;配合proxy_pass http://backend,不能靠斜杠硬凑
Header 里带下划线怎么办?
如果客户端发的是 X_User_Id: 123,但你在 map 里用 $http_x_user_id 总是空,八成是被 Nginx 默认过滤了。
- Nginx 默认忽略所有含下划线的 Header,因为 RFC 规定合法 Header 名只能含字母、数字、连字符
- 在
http或server块加一行:underscores_in_headers on; - 开启后,仍需按小写+下划线规则引用:
X_User_Id→$http_x_user_id,不是$http_x_user_id或$http_x_userid - 该设置不影响连字符命名的 Header(如
X-Api-Key),它们始终可用
真正容易翻车的不是语法写不对,而是 URI 值里混着空格、大小写混用、URL 编码字符、逗号分隔多值——map 和 location 都不做归一化,匹配不上就是匹配不上。











