Nginx rewrite 地址重写

rewrite 用于改写请求 URI:可实现 301/302 跳转、伪静态、域名迁移与 URL 规范化。它与 return 指令是"改地址"的两种主要手段,本章讲清语法、四个标志与典型场景。

rewrite 语法

rewrite 只能写在 server、location、if 块中,格式为"正则 + 替换串 + 标志":

rewrite regex replacement [flag];
server {
    listen 80;
    server_name example.com;
    rewrite ^/old/(.*)$ /new/$1 last;   # /old/a.html → /new/a.html
}

替换串中的 $1、$2 引用正则里的捕获组,$host、$request_uri 等内置变量也可使用。

四个标志的含义

标志行为典型用途
last停止当前 rewrite,用新 URI 重新匹配 location改写后想进入另一个 location
break停止 rewrite,直接用新 URI(不再重匹配)改写后仍留在当前块处理
redirect临时重定向,返回 302临时迁移、临时维护页
permanent永久重定向,返回 301换域名、URL 永久改变
location /download/ {
    rewrite ^/download/(.*)$ /files/$1 permanent;   # 外链随 301 转移到新地址
}

last 与 break 的区别

两者都会停止本次 rewrite 处理,区别在后续行为:last 用新 URI 重新走一遍 location 匹配(可能进入别的 location),break 则停留在当前 location 继续执行其内部指令:

location /api/ {
    rewrite ^/api/(.*)$ /v2/$1 break;   # 改写后仍在 /api/ 块内
    proxy_pass http://127.0.0.1:8080;   # 实际转发的新 URI 是 /v2/xxx
}

场景一:HTTP 跳 HTTPS

整站强制 https,推荐在 80 端口 server 里用 return 一次性完成(比 rewrite 简洁,也天然避免循环,见第 13 章):

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

等价写法:rewrite ^(.*)$ https://$host$1 permanent;

场景二:域名迁移

旧域名整体 301 到新域名,把搜索引擎权重平滑转移:

server {
    listen 80;
    server_name old-domain.com www.old-domain.com;
    rewrite ^(.*)$ http://www.new-domain.com$1 permanent;
}

场景三:伪静态

把 /article/123.html 这类地址在内部映射到动态脚本,浏览器地址栏不变、无 302:

location / {
    rewrite ^/article/([0-9]+)\.html$ /index.php?id=$1 last;
}

return 与 rewrite 怎么选

场景推荐
只要 301/302 状态码跳转return code url(最直接)
改写 URI 后交给其他 location 处理rewrite ... last
命中条件后想直接返回内容/状态码return code text

避免重定向循环

循环的典型成因:rewrite 把 /a 改成 /b,而 /b 又满足同一条 rewrite 条件,反复改写直至浏览器报"重定向过多"。规范做法:80 端口单独一个 server 只做 return 301,443 的 server 内部不再写协议跳转;确需条件判断时用 if ($scheme != "https") 包裹,且务必保证条件在改写后不再成立。

小结:rewrite 的核心是"正则改写 URI + 标志控制后续行为";纯跳转优先 return,内部路径改写用 last/break,跨站迁移用 permanent。拿不准是否循环时,用 curl -I 观察响应里的 Location 头即可判断。

笔记加载中…