Nginx rewrite规则需精准匹配、明确边界、区分重写与跳转:优先用location前缀匹配+精确rewrite,避免宽泛正则;rewrite内部重写用相对路径和last/break,301/302跳转宜用return;须过滤用户输入防open redirect和目录穿越,并注意执行顺序为location→rewrite→proxy_pass。

Nginx 的 rewrite 规则本身语法简洁,但真正用好需要理解匹配逻辑、执行顺序、变量作用域和重定向/重写的本质区别。高级配置不是堆砌复杂正则,而是让规则更可靠、可维护、不踩坑。
精准匹配路径,避免过度捕获
很多问题源于正则太宽泛,比如用 ^/.*$ 匹配所有请求,结果干扰静态资源或 API 接口。应优先使用前缀匹配(location)+ 精确 rewrite,再考虑正则。
- 用
location = /old处理完全相等的路径,比rewrite ^/old$ /new permanent;更高效且无歧义 - 需捕获参数时,明确限定边界:比如
rewrite ^/article/([0-9]+)/?$ /blog/$1/ last;,末尾/?允许带或不带斜杠,$防止匹配到/article/123abc - 避免在 rewrite 中重复写协议和域名,除非真要跨域跳转;内部重写用相对路径即可
区分 rewrite、return 和 internal 语义
很多人混淆这三者行为。rewrite 是内部重写 URI(不改变浏览器地址栏),return 是立即响应(可返回状态码或跳转),internal 标志决定是否允许内部访问。
- 要做 301/302 跳转,用
return 301 https://example.com$new_uri;比rewrite ... redirect更直接、少一层解析 - 想隐藏真实路径(如把
/api/代理到后端/v2/),用rewrite ^/api/(.*)$ /v2/$1 break;+proxy_pass http://backend;,注意break阻止后续 location 匹配 - 若 rewrite 后目标是内部 location(如
location /private { internal; ... }),必须加last或确保匹配到该 location,否则会 404
安全控制:防止 open redirect 和目录穿越
用户可控输入进 rewrite 变量(如 $args、$request_uri)时,必须过滤或校验,否则可能被利用。
- 避免直接拼接未过滤的参数:
rewrite ^/go/(.*)$ https://$1? permanent;是严重漏洞(可跳转任意站) - 限制跳转域名:先用 map 提取并白名单校验 host,再用于 rewrite;或改用后端逻辑处理跳转
- 防范
../:rewrite 目标路径不要直接包含用户输入的路径段;必要时用if ($request_uri ~* "\.\.") { return 403; }拦截
调试与生效顺序:location → rewrite → proxy_pass
rewrite 不是独立模块,它嵌套在 location 块中,执行时机和上下文很关键。一条规则是否生效,取决于它在哪个 location 里、用了什么 flag、有没有被后续规则覆盖。
-
last:停止当前 location 内所有 rewrite,重新匹配 location;break:停止当前块内 rewrite,继续执行本 location 后续指令(如 proxy_pass) - 多个 rewrite 在同一 location 中,按顺序执行,前面的修改会影响后面的 $1 $2 —— 注意捕获组是否被覆盖
- 开启
rewrite_log on;(配合error_log /path level notice;)可查看每条 rewrite 是否触发、匹配结果如何,但仅用于调试,线上关闭
不复杂但容易忽略:rewrite 是字符串操作,不解析 URL 编码,也不自动解码路径。如果原始请求含 %2F,它不会变成 /,需提前用 map 或 Lua 处理,或让上游保证编码规范。


















