规避 rewrite 死循环的关键是正确使用 break 和 last:break 终止重写阶段、不触发 location 重匹配;last 强制新 URI 重新走完整匹配流程,若仍命中原 location 则导致循环。

规避 rewrite 死循环,关键在于理解 break 和 last 对请求处理流程的控制差异:前者终止重写阶段、不触发 location 重匹配;后者终止当前处理、强制用新 URI 重新走完整匹配流程。错误地在 proxy_pass 场景下用 last,极易引发无限重入同一 location。
识别死循环高发场景
以下配置极易陷入循环:
- location /a/ 中 rewrite ^/a/(.*)\.html$ /a/$1.html last; + proxy_pass http://backend;
- rewrite 规则将 URI 改写为仍能匹配当前 location 的路径(如 /a/ → /a/);
- 使用 alias 时误配 break(alias 要求必须用 last,但若 rewrite 后路径又落入同 location,仍可能循环);
- 多个 rewrite 连续作用且未加限制,例如 rewrite /old /new; rewrite /new /old; 无 flag 控制。
用 break 切断匹配链,防止重入
当 rewrite 目的是内部路径调整、且后续应直接交由当前 location 的 proxy_pass 或 root 处理时,优先选 break:
- 它跳过本 location 内剩余 rewrite,也不再查找其他 location,直接进入后续阶段(如 proxy_pass);
- 适用于 /api/ → /v1/api/ 类型的前缀改写,改写后仍归属当前代理逻辑;
- 示例:rewrite ^/api/(.*)$ /v1/api/$1 break; 配合 proxy_pass http://upstream; 不会再次匹配 /api/ 或 /v1/api/ 的 location。
用 last 时必须确保新 URI 能跳出原 location
last 的本质是“重启匹配”,所以必须让重写后的 URI 不再命中当前 location 块:
- 改写目标应明确指向另一个 location(如 /static/ → /assets/,并另配 location /assets/);
- 或改写为根路径下可被 root / alias 直接服务的静态路径(如 /img/logo.png → /public/logo.png);
- 避免 rewrite 后仍落在正则 location ~ ^/a/ 或前缀 location /a/ 范围内;
- 调试时开启 rewrite_log on;,查看 error.log 中是否出现重复匹配同一 location 的日志行。
辅助手段加固防护
单靠 flag 不够,需叠加约束机制:
- 在 rewrite 前加 if 限制条件,例如 if (!-f $request_filename) { rewrite ... break; },避免对已存在文件反复重写;
- 用 return 404 或 return 444 主动截断异常路径,比依赖 rewrite 更可靠;
- 对敏感路径设置计数器变量(需配合 map 或 lua),超过 2 次匹配即拒绝,防兜底失效;
- 所有含 last 的 rewrite,务必在配置后手动模拟 URI 流转,验证是否真能跳出当前块。

















