Nginx 默认不跟随307重定向,需用error_page 307 = @handle_307拦截并proxy_pass $sent_http_location实现内部重发;若Location为内网地址,须重写或由后端返回公网可访问路径。

当 Nginx 作为反向代理时,如果后端服务返回了 307 Temporary Redirect,默认情况下 Nginx 不会自动跟随重定向,而是直接把 307 响应透传给客户端。这会导致浏览器收到 307 后自行跳转——但若目标地址是内网地址、带端口、或协议不匹配(如后端返回 http://localhost:8080/xxx),用户就无法访问。
让 Nginx 自动跟随并处理 307 重定向
核心思路:Nginx 本身不支持“自动重放请求”(不像 curl 的 -L),但可通过 error_page + proxy_pass 组合,将 307 视为需内部重试的错误,由 Nginx 主动发起新请求并返回 200 内容。
- 必须启用
error_page 307 = @handle_307;拦截原始 307 响应 - 在
@handle_307location 中用proxy_pass $sent_http_location;转发到响应头中的 Location 地址 - 确保后端返回的
Location是可被 Nginx 直接访问的地址(如http://backend-svc/xxx,而非http://localhost:8080/xxx) - 需要开启
underscores_in_headers on;(若后端自定义 header 含下划线)
基础配置示例(适用于同域后端)
假设后端返回的 Location 是相对路径或同域名下的绝对路径:
upstream backend {
server 127.0.0.1:8080;
}
<p>server {
listen 80;
server_name example.com;</p><pre class="brush:php;toolbar:false;">location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 拦截后端返回的 307,交由内部 location 处理
proxy_intercept_errors on;
error_page 307 = @handle_307;
}
location @handle_307 {
# 使用响应头中的 Location 发起新请求
proxy_pass $sent_http_location;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 防止循环(可选)
proxy_redirect off;
}}
处理 Location 为内网地址或需改写的场景
如果后端返回类似 Location: http://192.168.1.100:8080/new-path,Nginx 无法直接转发(可能网络不通或暴露内网)。这时需做地址重写:
- 用
map提取并替换$sent_http_location中的 host/port - 或改用
error_page 307 = @rewrite_307;,在@rewrite_307中用rewrite重写 URL,再proxy_pass - 更稳妥的方式:让后端返回符合代理拓扑的
Location(如通过X-Forwarded-Proto和Host动态生成 HTTPS + 公网域名地址)
注意与 HSTS 引发的 307 区分
如果浏览器反复出现 307 且跳转到 HTTPS,检查是否因后端响应含 Strict-Transport-Security(HSTS)头导致浏览器强制升级。这不是 Nginx 代理行为,而是浏览器缓存策略。此时应:
- 在 Nginx 中清除该 header:
proxy_hide_header Strict-Transport-Security; - 或让后端只在 HTTPS 响应中设置 HSTS,HTTP 响应不设











