rewrite 指令是 Nginx 核心功能之一,用于根据正则表达式规则修改请求的 URI,它通常用于实现 URL 美化(伪静态)、重定向、访问控制等场景。

(图片来源网络,侵删)
rewrite 指令的基本语法
rewrite 指令可以放在 server、location、if 等配置块中。
rewrite regex replacement [flag];
参数详解:
-
regex(必需)- 类型: 正则表达式。
- 作用: 用于匹配请求的 URI(不包括查询字符串,即 后面的内容)。
- 正则引擎: Nginx 使用 PCRE (Perl Compatible Regular Expressions) 库,因此支持大部分 Perl 风格的正则表达式。
- 变量匹配: 可以使用 或 来表示区分大小写和不区分大小写的匹配。
- 区分大小写匹配。
- 不区分大小写匹配。
- 区分大小写不匹配。
- 不区分大小写不匹配。
- 示例:
^/images/匹配以/images/开头的 URI。
-
replacement(必需)- 类型: 替换字符串。
- 作用: 当
regex匹配成功后,Nginx 会用这个字符串替换掉原始的 URI。 - 变量引用: 可以使用 Nginx 变量,
$1,$2... 来引用正则表达式中的捕获组。$&代表整个匹配的字符串。 - 示例:
regex是^/images/(.*)$,replacement是/img/$1,那么请求/images/foo/bar.jpg会被重写为/img/foo/bar.jpg。
-
[flag](可选)
(图片来源网络,侵删)- 类型: 标志位。
- 作用: 决定
rewrite指令执行后的行为,例如是否继续检查后续的rewrite规则、是否重定向等,这是rewrite指令最关键的部分。
[flag] 标志位详解
标志位控制着 rewrite 的“命运”,理解它们至关重要。
last
- 行为: 当前的
rewrite规则执行完毕后,Nginx 停止 在当前location中继续执行后续的rewrite规则,Nginx 会用新的 URI 重新发起一次请求,并根据这个新的 URI 在server标签中查找匹配的location。 - 使用场景: 通常用于在一个
location块中完成重写,然后交由另一个location块处理。 - 注意:
last可能会导致循环重写,如果配置不当会造成无限循环。
break
- 行为: 当前的
rewrite规则执行完毕后,Nginx 停止 在当前location中继续执行后续的rewrite规则,它不会重新发起请求,而是在当前location中继续处理,例如访问location中指定的root目录下的文件。 - 使用场景: 当你只想修改 URI,并希望请求在当前
location内部处理时使用,将/abc重写为/def,然后直接访问/def对应的文件。 - 注意:
break之后,Nginx 会尝试处理重写后的 URI,但不会再次触发rewrite指令。
redirect
- 行为: 返回一个 302 (临时重定向) 的 HTTP 状态码给客户端。
- 行为细节: 客户端浏览器会收到一个 302 响应,并在响应头中看到
Location字段,其值为replacement指定的 URI,浏览器会根据这个地址发起一个新的 GET 请求。 - 特点:
replacement字符串必须是完整的、以http://或https://开头的绝对路径,否则浏览器可能无法正确解析。 - 使用场景: 临时性地将旧 URL 指向新 URL,例如网站维护、临时页面跳转。
permanent
- 行为: 返回一个 301 (永久重定向) 的 HTTP 状态码给客户端。
- 行为细节: 与
redirect类似,但 301 重定向具有“永久性”。 - 特点: 浏览器会缓存这个重定向关系,下次用户再访问旧 URL 时,浏览器可能会直接从缓存中读取新地址,而不会再次向服务器请求,同样,
replacement也必须是绝对路径。 - 使用场景: URL 结构永久性变更,例如将
blog.example.com的流量永久重定向到www.example.com/blog。
last vs. break 的核心区别
这是一个非常容易混淆的点,用一个例子就能说清楚。
假设我们有如下配置:
server {
listen 80;
server_name example.com;
location /old {
rewrite ^/old/(.*)$ /new/$1 last; # 规则1
rewrite ^/new/(.*)$ /final/$1 break; # 规则2
# ... 其他 location 配置
}
location /new {
rewrite ^/new/(.*)$ /another/$1 last; # 规则3
# ... 其他 location 配置
}
location /final {
echo "最终匹配到 /final";
}
}
场景1:请求 /old/test
- 请求进入
location /old。 - 规则1 匹配成功,将 URI 重写为
/new/test,并使用last标志。 last行为: Nginx 停止在location /old内部继续处理,它使用新的 URI/new/test重新发起一次查找。- Nginx 在
server块中寻找匹配/new/test的location,找到了location /new。 - 请求现在在
location /new中处理。 - 规则3 匹配成功,将 URI 重写为
/another/test,并使用last标志。 last行为: 再次停止,用/another/test重新查找location,假设没有匹配的location,则返回 404。- 最终结果:
/another/test对应的 404 页面。
场景2:请求 /new/test (直接访问)
- 请求直接进入
location /new。 - 规则3 匹配成功,将 URI 重写为
/another/test,并使用last标志。 last行为: 停止,用/another/test重新查找location,假设没有匹配的location,则返回 404。- 最终结果:
/another/test对应的 404 页面。
综合示例
示例1:URL 伪静态(SEO优化)
将动态的 index.php?id=123 格式转换为静态的 /article/123 格式。

(图片来源网络,侵删)
server {
listen 80;
server_name example.com;
root /var/www/html;
# 当请求是 /article/123 这样的格式时
location /article/ {
# 将 /article/123 重写为 /index.php?id=123
# 使用 break,因为重写后 Nginx 会直接请求 /index.php 文件
rewrite ^/article/(\d+)$ /index.php?id=$1 break;
}
# 处理所有对 /index.php 的请求
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
示例2:域名重定向(HTTP -> HTTPS & WWW)
将 http://example.com 和 http://www.example.com 永久重定向到 https://www.example.com。
server {
listen 80;
server_name example.com www.example.com;
# 使用 permanent 返回 301 永久重定向
# replacement 必须是完整的 URL
rewrite ^(.*)$ https://www.example.com$1 permanent;
}
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
# ... 其他 SSL 和网站配置
}
示例3:访问控制
禁止特定 IP 访问网站,并返回 403。
server {
listen 80;
server_name example.com;
# 如果客户端 IP 是 192.168.1.100
if ($remote_addr = "192.168.1.100") {
# 重写到一个不存在的路径,break,这样就会找不到文件返回 404
# 或者直接返回 403
return 403;
# rewrite ^ /forbidden.html break; // 另一种方式
}
# ... 正常的网站配置
}
重要注意事项
- 正则表达式顺序: Nginx 按照配置文件中的顺序依次执行
rewrite规则,直到匹配到一条带有last或break标志的规则,或者执行完所有规则。 - 性能影响: 过多的
rewrite规则会增加 Nginx 的匹配开销,影响性能,应尽量避免使用过于复杂的正则表达式。 - 循环重定向: 使用
last时要特别小心,如果重写后的 URI 经过location匹配后又回到了原始的rewrite规则,就会形成无限循环,Nginx 有一个内置的max_redirects限制(默认为10次),超过后会返回 500 错误。 rewrite_log:rewrite规则不生效,可以开启rewrite_log来调试。http { rewrite_log on; # 开启重写日志 error_log /var/log/nginx/error.log notice; # 日志级别需要为 notice 或更详细 # ... }日志中会显示
rewrite的匹配和执行过程。
希望这份详细的解释能帮助你完全掌握 Nginx 的 rewrite 指令!
