nginx rewrite 是在 location 匹配之后、内容生成之前执行的 uri 改写机制,改写后默认触发内部重匹配;典型应用包括 http 跳 https、伪静态路由(需用 last)、域名迁移(用 permanent),须规避 if 嵌套、last/break 混用及 proxy_pass 路径拼接错误。

Nginx rewrite 是 Linux 环境下 URL 路由控制的核心手段,不是“改个地址就完事”,而是牵一发而动全身的请求流程干预。它真正起效的位置在 location 匹配之后、内容生成之前,且 rewrite 后若 URI 变化,默认会触发一次内部重匹配——这个机制是多数问题的根源,也是高效配置的关键。
常见经典场景与对应写法
强制 HTTP 跳 HTTPS
最稳妥写法是 server 块级处理,避免 location 内部反复跳转:
- server { listen 80; server_name example.com; return 301 https://$server_name$request_uri; }
不建议用 rewrite ^(.*)$ https://$server_name$1 permanent,因正则开销略高,且 $1 在某些版本中可能为空导致跳转异常。
伪静态路由(如 /article/123.html → /index.php?id=123)
必须配合 last,让改写后重新走 location 匹配,才能进到 PHP 处理块:
- location / { rewrite ^/article/(\d+)\.html$ /index.php?id=$1 last; }
- location ~ \.php$ { fastcgi_pass php_backend; ... }
若用 break,则 rewrite 后不会再次匹配 .php,直接尝试找 /index.php?id=123 这个静态文件,报 404。
多级目录扁平化(如 /product/123/detail → /p_123.html)
适合前端资源静态化或 CDN 缓存优化:
- location /product { rewrite ^/product/(\d+)/detail /p_$1.html break; }
这里用 break 是因为目标已是最终静态路径,无需再匹配其他 location;proxy_pass 不在此处生效,除非你额外加了代理逻辑。
旧域名迁移(old.com → new.com)
需全路径保留,用 permanent 实现 SEO 友好跳转:
- server { server_name old.com; rewrite ^(.*)$ https://new.com$1 permanent; }
注意:不能写成 rewrite ^/.*$ https://new.com/ permanent,否则丢失路径参数。
在无 root/sudo 权限的环境(云容器、VPS、隔离主机)中安装并配置 OpenClaw 浏览器工具的 headless Chrome。适用场景:...
必须避开的几个高频坑
if + rewrite 的组合陷阱
Nginx 中 if 是伪指令,不在标准请求处理流中,容易引发不可预期行为。例如:
- if ($args ~ "utm_source") { rewrite ^(.*)$ $1? permanent; } —— 这会导致参数清空后无限重定向
- 更安全做法:用 map 指令预定义变量,再在 rewrite 中引用
last 和 break 混用错位
二者核心区别在于是否触发新 location 匹配:
- last:改写 URI → 终止当前 location 内所有 rewrite → 拿新 URI 重新选 location
- break:改写 URI → 终止所有 rewrite → 就地继续执行当前 location 剩余指令(如 proxy_pass)
典型错误:在带 proxy_pass 的 location 里用了 last,结果新 URI 又掉进另一个 proxy_pass 块,造成二次转发或 502。
proxy_pass 与 rewrite 的 URI 拼接问题
当 proxy_pass 后不带 URI(如 proxy_pass http://backend),rewrite 改写的路径会完整透传;若带路径(如 proxy_pass http://backend/api/),则 rewrite 的前缀会被剥离:
- location /old { rewrite ^/old/(.*)$ /new/$1 break; proxy_pass http://backend; } → 实际请求 backend 的是 /new/xxx
- location /old { rewrite ^/old/(.*)$ /api/$1 break; proxy_pass http://backend/; } → 实际请求是 http://backend/api/xxx(/old 被替换为 /api)
调试与验证建议
开启 rewrite 日志快速定位问题
在 http 或 server 块中加:
- rewrite_log on;
- error_log /var/log/nginx/error.log notice;
日志中会出现 “using configuration”、“rewritten data” 等关键行,能看清每一步 URI 变化和 location 切换过程。
用 curl 验证跳转行为
区分 301/302 和内部重写:
- curl -I http://example.com/old/path → 看是否有 Location 头,确认是否真跳转
- curl -v http://example.com/internal-rewrite-path → 看实际响应 body 和状态码,判断是否内部改写成功
别只靠浏览器访问,浏览器会缓存 301,干扰判断。
rewrite 不复杂,但容易忽略执行时机和上下文影响。把 last/break 分清、避开 if、理清 proxy_pass 的路径处理逻辑,90% 的问题就能预防。










