四个 flag 对照表
| flag | 行为 | 后续 |
|---|---|---|
| last | 改写 URI 后重新走一遍 location 匹配 | 新 URI 可能命中别的 location |
| break | 改写 URI 后停在当前 location | 直接用改写后的 URI 干活 |
| redirect | 返回 302 临时重定向 | 浏览器重新发请求到新地址 |
| permanent | 返回 301 永久重定向 | 浏览器/搜索引擎缓存跳转 |
last 与 break 的区别只在"改写后要不要重新匹配 location":想链式改写用 last(改完让别的 location 接手),改完就在本地处理用 break。301 与 302 的区别在浏览器缓存:301 会被浏览器永久记住——域名迁移用 301 传权重给 SEO,但配错了很难纠正(用户浏览器不再问你),没把握先用 302 试,确认无误再切 301。
return 才是首选
# 纯重定向:return 一行搞定,不碰 rewrite
server {
listen 80;
return 301 https://$host$request_uri; # 上一章 HTTPS 跳转就是它
}
# rewrite 该出场的地方:不换地址,只换内部路径
location /old-app/ {
rewrite ^/old-app/(.*)$ /new-app/$1 last; # 内部改写,用户无感
}
# 版本化资源改写:/v2/static/xx 实际读 /static/xx
location /v2/ {
rewrite ^/v2/(.*)$ /$1 break;
alias /data/www/;
}
#
# rewrite 匹配的是去斜杠后的 URI(不含参数)
# 参数(?后的部分)自动保留,要丢弃得在末尾加问号:rewrite ... ?;if 的是非
Nginx 官方名言:"If is Evil"。if 在 location 内的执行顺序反直觉,嵌套 if 更是行为难料。判断逻辑优先用这些替代品:按前缀分流用 location;按请求头/变量取值用 map(限流白名单篇用过);单纯跳转用 return。if 只在两处相对安全:server 顶层做 return/rewrite,以及配合 !-f 这类文件判断。看别人配置里一坨 if 时先起疑心,多半能改写成更稳的结构。
三个实战案例
# ① 旧域名整体迁移(302 验证期,稳定后换 301)
server {
server_name old.example.com;
return 302 https://new.example.com$request_uri;
}
# ② 统一去掉 index.php
location / {
rewrite ^(.*)/index.php$ $1 permanent;
}
# ③ 静态资源加版本号前缀,内部剥掉
location ~ ^/v(d+)/static/ {
rewrite ^/vd+(.*)$ $1 break;
root /data/www;
expires 365d; # 前端改版本号 = 天然缓存刷新(呼应动静分离篇)
}调试
rewrite 不生效先开 rewrite_log on;(配 error_log notice 级),每一步改写都会打日志:正则有没有匹配、改写成了什么、走了哪个 flag,一目了然。外部验证用 curl -I 看跳转链——301 会不会连环跳、最终落到哪,一眼看清。下一篇接一种特殊的流量:WebSocket 长连接。
评论 (0)