重定向死循环源于rewrite规则反复触发而非跳转次数过多;应使用break替代last进行内部路径改写,外部跳转优先用return,精确控制location匹配范围,并在反向代理中透传X-Forwarded-Proto等协议头。

重定向死循环不是“跳太多次”造成的,而是 rewrite 规则在内部反复触发、不断重匹配 location 导致的。Nginx 默认最多重试 10 次,超限就返回 500 错误;浏览器看到连续多次 301/302 跳转,则报 ERR_TOO_MANY_REDIRECTS。关键不在跳转次数本身,而在规则设计是否让请求“兜圈子”。
用 break 替代 last 做内部路径改写
当 rewrite 目的是调整路径后继续由当前 location 处理(比如 proxy_pass 或 root 服务),必须用 break ——它改完 URI 就停在当前 location,不再重新匹配。
- 错误写法:
rewrite ^/api/(.*)$ /v1/api/$1 last;→ 改写后 /v1/api/ 可能仍命中该 location,再次触发 rewrite - 正确写法:
rewrite ^/api/(.*)$ /v1/api/$1 break;→ 改写后直接走 proxy_pass,不回头 - 特别注意:alias 指令必须配合 last,但要确保 rewrite 后路径不会再次落入同一 location 范围
外部跳转优先用 return,不用 rewrite permanent
需要浏览器地址栏变化(如 HTTP → HTTPS、域名跳转),return 比 rewrite 更安全、更高效,且不会参与 location 匹配流程。
- 推荐:
return 301 https://$host$request_uri;或return 301 http://www.example.com$request_uri; - 避免:
rewrite ^ http://www.example.com$request_uri permanent;—— 容易因 server_name 或 location 范围过宽导致循环 - 多个域名跳转时,server_name 只写源域名,不要把目标域名也加进去(例如只写
shidongyun.com,别写www.shidongyun.com)
精确控制 location 匹配范围
location 匹配太宽是循环的温床。rewrite 后的新路径只要还能进同一个 location,就可能再执行一遍规则。
- 用
location = /exact或location ^~ /static/替代模糊的location / - 正则 location 要加锚点:
location ~ ^/old/比location ~ /old/更安全,防止 /new/old/ 也被捕获 - 检查 rewrite 目标是否落在其他 location 的覆盖范围内,必要时单独为新路径配置 location 块
反向代理场景必须透传协议头
后端应用(如 Django、Spring Boot)若不知道用户真实访问协议,会自己发起跳转,和 Nginx 的跳转形成嵌套循环。
- 在 proxy_pass 所在 location 中加:
proxy_set_header X-Forwarded-Proto $scheme; - 同时传:
proxy_set_header Host $host;、proxy_set_header X-Real-IP $remote_addr; - 后端框架需配置信任这些头(例如 Laravel 的
APP_TRUSTED_PROXIES,Django 的SECURE_PROXY_SSL_HEADER) - CDN 环境下改用:
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;


















