关键不是“加更多规则”,而是切断跳转链、消除循环条件、确保单次直达:归并多级跳转为单次return 301,禁用if+rewrite,改用location精确匹配或map预查表,并分离源域与目标域的server块避免server_name冲突。

避免 Nginx 中 301 重定向次数过多(ERR_TOO_MANY_REDIRECTS),关键不是“加更多规则”,而是切断跳转链、消除循环条件、确保单次直达。浏览器报错本质是请求在旧地址和新地址之间反复横跳,通常 20 次就终止。问题多藏在配置逻辑里,而非语法错误。
检查并归并跳转路径,只留一次 301
逐条排查所有 server 和 location 块里的 return 301、rewrite permanent、rewrite redirect。重点看是否存在:
- /old → /temp → /new 这类中间跳转(必须删掉 /temp 环节)
- HTTP 跳 HTTPS 后,又因 CDN 或反向代理把 HTTPS 请求误判为 HTTP,再次触发跳转
- 域名统一配置中,www 和非 www 的 server 块互相 redirect(如 A 块跳 B,B 块又跳回 A)
验证方式:用 curl -I http://yoursite.com/old-path 查看响应头中的 Location,确认它直接指向最终目标,且状态码就是 301,不经过任何中转。
慎用 if + rewrite,优先用 return 或 map
if 在 location 外使用有已知缺陷;在 location 内嵌套 rewrite 更易引发隐式循环。替代方案更安全:
- 单路径跳转(如 /a.html → /b.html):用
location = /a.html { return 301 /b.html; } - 整站换域(old.com → new.com):在 old.com 的 server 块中写
return 301 https://new.com$request_uri; - 批量路径映射(超 5 条):改用
map模块预定义映射表,查询快、无顺序判断开销
注意 server_name 和 rewrite 目标不要冲突
常见死循环源头:rewrite 要跳转的目标域名,被同时写进了当前 server 的 server_name 列表。
- 错误示例:
server_name a.com b.com; rewrite ^/(.*)$ http://b.com/$1 permanent;→ b.com 请求进来也会匹配该块,无限循环 - 正确做法:为跳转源单独设一个 server 块,
server_name只写 a.com;跳转目标 b.com 由另一个独立 server 块处理 - HTTPS 场景下尤其注意:别在
listen 443 ssl块里写跳到 HTTP 的规则,协议不匹配反而导致 fallback 到其他块继续跳
关闭多余重定向头,避免与外部服务叠加
后端应用(如 PHP、Node.js)也可能返回 301,和 Nginx 层叠后形成双跳:
- 检查应用代码是否含
header("Location: ...")或框架级重定向逻辑 - Nginx 配置中禁用可能干扰的指令,如
try_files $uri $uri/ /index.php?$query_string;后紧跟 rewrite,容易因 URI 变更触发二次匹配 - 若使用 Cloudflare 或其他 CDN,确认其“Always Use HTTPS”或“Forwarding URL”功能未与 Nginx 规则重复生效











