nginx中实现内部代理转发需用rewrite ... last;触发内部重定向,再由匹配的location执行proxy_pass;更推荐直接用proxy_pass末尾带/自动截断路径,或用map实现动态后端选择。

直接在 rewrite 指令中做反向代理转发是不可行的,因为 rewrite 仅负责 URI 重写和跳转(包括内部重定向或外部重定向),它本身不触发代理行为。要实现“内部转发”而非显式 302 跳转,关键在于:**用 rewrite ... last; 触发内部重定向,再配合 location 块匹配新 URI 并启用 proxy_pass**。
用 rewrite + location 实现内部代理转发
这是最常用且可靠的方式。Nginx 先重写请求路径,然后通过 last 标志让引擎重新匹配 location,再在匹配到的 location 中执行反向代理。
-
rewrite 必须加
last:否则会变成外部 302(默认)或终止处理(break) -
重写后的 URI 需能被某个
location精确或前缀匹配到,该 location 内配置proxy_pass -
proxy_pass 后端地址应与原始请求无关,可指向内部服务(如
http://127.0.0.1:8000)
示例:将 /api/v1/user 内部转发到后端 http://backend:8000/user
location /api/ {
rewrite ^/api/(.*)$ /$1 last;
}
location / {
proxy_pass http://backend:8000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
说明:访问 /api/v1/user → 重写为 /v1/user → 匹配 location / → 代理到 http://backend:8000/v1/user。整个过程对客户端透明,无 302。
避免 rewrite,直接用 location + proxy_pass 更简洁
如果只是路径映射,通常无需 rewrite —— 直接在 location 中用 proxy_pass 的路径截断机制更清晰、更高效。
-
proxy_pass末尾带/:会删除 location 匹配前缀,再拼接后端路径 -
proxy_pass末尾不带/:保留原始 URI 全路径转发
等效上例的写法:
location /api/ {
proxy_pass http://backend:8000/;
proxy_set_header Host $host;
}
访问 /api/v1/user → 自动转发为 http://backend:8000/v1/user。无需 rewrite,语义明确,性能更好。
需要动态路径拼接?用 map + proxy_pass
当转发目标依赖变量(如 host、参数、header),可用 map 预定义后端地址,再在 location 中引用。
map $host $backend {
~^app\.example\.com$ http://app-svc:3000;
~^api\.example\.com$ http://api-svc:8000;
default http://fallback:8080;
}
server {
location / {
proxy_pass $backend;
proxy_set_header Host $host;
}
}
这样既避免 rewrite 的复杂性,又能根据条件灵活选择上游,仍属内部转发,无 302。
注意 rewrite 和 proxy_pass 的路径处理细节
容易出错的是路径拼接逻辑:
-
rewrite ^/old/(.*)$ /new/$1 break;→break不触发 location 重匹配,后续 proxy_pass 若在同 location 内,仍用原始 URI -
location /old/ { proxy_pass http://upstream/new/; }→ 请求/old/a会转发为/new/a(自动截断+拼接) -
location /old/ { proxy_pass http://upstream; }→ 请求/old/a会转发为/old/a(完整路径透传)
务必验证实际转发的 upstream URI,可通过 error_log notice 或抓包确认。











