Nginx rewrite应优先用内部重写实现静默映射,仅对外公开旧链接才用301;需区分redirect与internal、合理使用last/break、捕获变量重组路径、控制query string、加日志与兜底验证。

Nginx 的 rewrite 可以高效实现旧 URL 到新结构的平滑映射,关键在于理解匹配顺序、捕获变量和重定向/内部重写的区别。不建议盲目用 301 跳转,多数场景应优先用内部重写(无状态、不暴露新路径),仅对已对外公开的旧链接才做 301。
明确 rewrite 类型:redirect 还是 internal?
rewrite 默认是内部重写(类似 Apache 的 [L] + 内部跳转),浏览器地址栏不变;加 permanent 或 redirect 才触发 HTTP 状态码跳转:
-
内部重写(推荐用于后端适配):用户仍访问
/old/product/123,Nginx 静默转发到/v2/items/123,后端按新规则处理 -
301 重定向(仅用于 SEO 迁移或外部链接兼容):返回
Location: /v2/items/123,浏览器地址栏变化,搜索引擎会更新索引
用正则捕获多级路径并重组
旧路径如 /category/books/author/tolkien/page/2 映射到 /v2/search?cat=books&author=tolkien&page=2,需分组捕获:
location /category/ {
rewrite ^/category/([^/]+)/author/([^/]+)/page/(\d+)$ /v2/search?cat=$1&author=$2&page=$3 last;
}注意:
- ^/category/ 是匹配前缀,后面用 () 捕获关键段
- $1、$2、$3 对应各组内容
- last 表示终止当前 location 匹配,重新匹配新 URI(适合内部重写)
- 若想直接交给后端,也可用 break(不重新匹配,直接用当前 location 处理)
处理带扩展名或参数的旧链接
旧站可能有 /news/2023/04/article.php?id=100,需同时处理路径和 query string:
- Nginx 默认保留原始 query string,所以
rewrite ... /v2/post/100? permanent;会自动带上?id=100 - 若要丢弃旧参数、只用新结构,结尾加
?(问号结束):rewrite ... /v2/post/100? permanent; - 若需提取参数值(如
id=100),可配合if+$args,但更稳的方式是让后端解析,或用map提前提取
避免循环和遗漏:加兜底与日志验证
多级 rewrite 容易因正则过宽或 location 嵌套引发循环(如 500 错误)。上线前务必:
- 在对应 location 中加
rewrite_log on;(需编译时启用 debug 日志),配合error_log /var/log/nginx/rewrite.log notice;查看重写过程 - 用
return 404 "Legacy path not migrated";或return 302 /404.html;给未覆盖的旧路径设兜底 - 测试典型路径:
curl -I http://site/old/path看状态码和 Location 头,确认是否符合预期
rewrite 不复杂但容易忽略匹配优先级和作用域。把旧路径规律列出来,一条条写正则、加测试,比堆一堆泛匹配更可靠。


















