nginx url重写依赖rewrite指令,flag选错、位置放错或正则写错任一都会导致跳转失效、循环重定向或500错误;rewrite应优先置于server或location块中,避免在if中使用;last触发新uri重新匹配location,break则在当前location内继续处理;redirect和permanent仅在replacement以http://、https://或$scheme://开头时才触发浏览器跳转。

直接说结论:Nginx 的 URL 重写靠 rewrite 指令,但 flag 选错、位置放错、正则写错,三者任一出问题都会导致跳转不生效、循环重定向或 500 错误。
rewrite 放在哪?server / location / if 的区别必须分清
很多人把 rewrite 塞进 if 块里,结果偶发失效或匹配异常——官方明确不推荐在 if 中用 rewrite,因为 if 是配置解析期判断,而 rewrite 是请求处理期执行,语义和时机不一致。
-
server块里的rewrite对所有请求生效,适合全局跳转(如强制 HTTPS) -
location块里的rewrite只对匹配该路径的请求起作用,最常用也最安全 -
if块中仅允许极少数场景(如检查$args或$host),且必须配合return或set,避免嵌套rewrite
last 和 break 到底怎么选?关键看要不要重新走匹配流程
last 和 break 都会终止当前块内后续 rewrite 执行,但行为完全不同:
-
last:重写后的新 URI 会**重新进入 server 匹配流程**,可能命中另一个location—— 容易引发循环(比如rewrite /a /b last+rewrite /b /a last),Nginx 限制最多 10 次重试,超限返回 500 -
break:重写后**不再重新匹配**,直接用新 URI 在当前location内继续处理(比如找文件、proxy_pass)—— 更可控,适合内部路径改写 - 常见误用:
location /api { rewrite ^/api/(.*)$ /v2/$1 last; }→ 新 URI/v2/xxx可能没对应location /v2,结果 404;换成break就直接在当前location下找/v2/xxx文件
redirect 和 permanent 怎么触发浏览器跳转?别漏协议头
这两个 flag 的本质是返回 HTTP 状态码(302 / 301),但有个硬性条件:replacement 字符串**必须以 http://、https:// 或 $scheme:// 开头**,否则 Nginx 当作内部重写处理,不会跳转。
- 正确写法:
rewrite ^/old.html$ https://example.com/new.html permanent; - 错误写法:
rewrite ^/old.html$ /new.html permanent;→ 实际效果等同于last,地址栏不变,只是内部重写 - 安全建议:用
$scheme代替硬编码协议,避免 HTTP/HTTPS 混用:rewrite ^/login$ $scheme://$host/auth permanent;
正则捕获和变量引用容易踩哪些坑?
正则里用 () 捕获的内容,通过 $1、$2 引用,但注意:
-
$1只在当前rewrite行有效,不能跨行传递;想复用需用set提前存到变量 - 路径开头的
/必须显式匹配,rewrite ^abc /def不会匹配/abc,得写成rewrite ^/abc /def - 结尾斜杠要小心:
^/post/(.*)/$不匹配/post/123,而^/post/(.*)/?$才兼容有无斜杠两种情况 - 中文或特殊字符需用
~*(不区分大小写)或转义,比如匹配含空格路径:rewrite "^/file name\.txt$" /safe.txt break;(整个正则用双引号包裹)
真正麻烦的从来不是写对一行 rewrite,而是它嵌在 location 层级、flag 行为、正则边界和变量生命周期交织的上下文中——改完记得用 nginx -t 检查语法,再用 curl -I 看实际响应头,别只靠浏览器刷新判断。











