做 Nginx 配置的时候,rewrite 指令大家肯定不陌生,但后面的 flag 参数——last、break、redirect、permanent——很多人搞不清楚什么时候该用哪个。用错了轻则不生效,重则导致死循环返回 500 错误。今天把这四个 flag 一次性讲透。
先弄懂 rewrite 指令的基础语法
Nginx 官方文档对 rewrite 的定义是:用正则表达式匹配请求 URI,匹配上了就按 replacement 字符串改写 URI。语法是这样的:
rewrite regex replacement [flag];
举个例子,把下载路径中的 /media/ 替换成 /mp3/:
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
这里的关键就是最后那个 flag——它决定了改写完之后 Nginx 接下来干什么。
四个 flag 一一拆解
1. last——重新搜索 location
带 last flag 时,Nginx 会停止执行当前 server 块内剩余的 rewrite 指令,然后以新的 URI 重新搜索一遍 location 匹配规则,再在新匹配到的 location 里继续处理。
典型场景:需要多级内部跳转,比如在一个 server 块里做多次规则匹配。
server {
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last;
return 403; # 只有上面两条都不匹配才走到这里
}
2. break——停在当前 context
break 和 last 名字差不多,但行为完全不同。break 同样是停止执行当前 rewrite 指令集,但不会重新搜索 location,直接在这个 location 里继续处理后续请求。
简单说:last 跳转,break 不跳转。
location /download/ {
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;
rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra break;
return 403;
}
注意:如果在 /download/ 这个 location 里用了 last 而不是 break,Nginx 会重新搜索 location,导致最多 10 次循环后返回 500 错误。官方文档专门指出了这个坑。
3. redirect——返回 302 临时重定向
redirect 会告诉浏览器:「这个页面临时搬走了,请去新地址看看」,返回 302 状态码。浏览器收到 302 后会自己跳转到新地址,下次访问还是先请求旧地址。
rewrite ^/old-page(.*)$ /new-page$1 redirect;
如果 replacement 字符串以 http://、https:// 或 $scheme 开头,即使不写 redirect flag,Nginx 也会默认返回 302 重定向。
4. permanent——返回 301 永久重定向
permanent 返回 301 状态码,告诉浏览器和搜索引擎:「这个页面永久迁移了,请记住新地址」,浏览器会缓存这个跳转。
rewrite ^/old-page(.*)$ https://example.com/new-page$1 permanent;
做 HTTPS 迁移或者域名更换时,通常会用 permanent 而不是 redirect,因为 301 能传递搜索引擎权重。
一张表总结四个 flag 的区别
| Flag | 是否重搜索 location | 返回给浏览器 | 是否缓存 | 典型场景 |
|---|---|---|---|---|
last | ✅ 重新搜索 | 无(内部跳转) | — | 多级 rewrite 链 |
break | ❌ 不重搜索 | 无(内部跳转) | — | 单个 location 内的 URI 改写 |
redirect | — | 302 临时重定向 | ❌ 不缓存 | 临时迁移、灰度发布 |
permanent | — | 301 永久重定向 | ✅ 浏览器缓存 | 域名更换、HTTPS 迁移 |
实战中容易踩的几个坑
坑一:location 里用了 last 导致循环
这是最常见的错误。在 location 块内使用 last 会触发重新搜索 location,如果正则没写好,很容易形成「rewrite → 匹配同一 location → 再 rewrite」的死循环,Nginx 默认限制最多 10 次,超过就返回 500。
解决方法:location 块内用 break,server 块顶层的 rewrite 才用 last。
坑二:redirect 和 permanent 用错场景
如果不确定是否要永久迁移,先用 redirect(302)。一旦设了 permanent(301),浏览器会长期缓存,搜索引擎也会更新索引,后面想改回来就麻烦了。
坑三:rewrite 后面参数被重复追加
如果 replacement 字符串里带了新参数,旧参数会自动追加在后面:
# 请求: /show?user=john
# rewrite 后: /show?user=jane&user=john ← 参数重复了!
rewrite ^/users/(.*)$ /show?user=$1 last;
解决方法:在 replacement 末尾加个 ? 阻止追加旧参数:
rewrite ^/users/(.*)$ /show?user=$1? last;
坑四:正则里的大括号和分号要加引号
如果正则表达式包含 } 或 ; 字符,整个正则必须用引号包起来:
rewrite "^(.*)\.(js|css)$" /static/$1.$2 break;
常见配置实例
例1:把旧域名请求重定向到新域名(301 永久)
server {
listen 80;
server_name old-example.com;
rewrite ^/(.*)$ https://new-example.com/$1 permanent;
}
例2:临时维护页面(302)
rewrite ^/.*$ /maintenance.html redirect;
例3:去掉 URL 中的尾巴(比如 .html 后缀标准化)
location / {
rewrite ^(.+)\.html$ $1 break;
try_files $uri $uri/ /index.html;
}
例4:基于正则的多条件 rewrite(last)
server {
rewrite ^/article/(\d+)$ /post?id=$1 last;
rewrite ^/page/(\d+)$ /index?p=$1 last;
# 都匹配不上就走默认处理
}
总结
Nginx rewrite 的四个 flag 看似简单,实际上涉及到 location 匹配规则、请求处理流程等多个知识点。记住两个核心区别:
- last vs break:前者会重新搜索 location,后者不会;前者用于 server 顶层,后者用于 location 内部。
- redirect vs permanent:前者 302 浏览器不缓存,后者 301 浏览器会缓存,SEO 效果不同。
配置之前先想清楚需求:是浏览器要跳转(redirect/permanent),还是 Nginx 内部改写 URI(last/break)?方向对了,配置才不会白写。
相关推荐:
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论