目录
Nginx 的 rewrite指令是实现 URL 重写与重定向的核心工具,对于网站维护、SEO 优化和提升用户体验都至关重要。下面将详细解析其用法,并汇总生产环境中的实用案例。
一. 理解 rewrite 指令
rewrite指令允许你使用正则表达式来改变请求的 URI,其基本语法如下:
rewrite regex replacement [flag];
-
regex:用于匹配当前请求 URI 的正则表达式。
-
replacement:匹配成功后,用于替换的新字符串。如果以
http://、https://或$scheme开头,则会直接向客户端返回重定向。 -
flag:可选标志,用于控制重写行为 。
二. 掌握关键 Flag
理解并正确使用 flag是避免配置错误的关键。不同 flag的行为差异如下表所示 :
| Flag | 作用 | 典型应用场景 |
|---|---|---|
| last | 停止当前所有 | 将请求重写到内部一个新的 URI,需要经过标准的 location 匹配流程。 |
| break | 停止当前所有 | 重写后直接映射到文件系统的一个具体路径。 |
| redirect | 返回 302 临时重定向给浏览器,浏览器地址栏会显示新的 URL。 | 临时性的跳转。 |
| permanent | 返回 301 永久重定向给浏览器,浏览器和搜索引擎会更新记录。 | 域名永久变更、URL 结构永久改变,有利于 SEO 。 |
重要提示:
last和break都用于内部重写(浏览器地址栏不变),而redirect和permanent用于外部重定向(浏览器地址栏改变)。
三. 相关指令与变量
除了 rewrite,还有一些指令和内置变量在编写规则时非常有用:
-
if 指令:用于条件判断,但应谨慎使用,因为某些情况下可能导致难以预料的行为 。例如,根据用户代理或请求方法进行重写。
-
set 指令:用于定义自定义变量,存储中间值,使配置更灵活 。
-
return 指令:直接返回指定的状态码或跳转到 URL,比用
rewrite做简单重定向更高效 。例如,return 301 https://$host$request_uri;可用于强制跳转 HTTPS。 -
常用变量:
-
$request_uri:包含原始请求的完整 URI(包括查询参数)。 -
$args或$query_string:仅包含查询参数。 -
$scheme:请求使用的协议(http 或 https)。 -
$host:请求的主机名 。
-
四. 生产环境实践案例
以下案例均来自生产环境,你可以根据需求调整使用。
1. 域名规范化与 HTTPS 强制跳转
这是最常见的配置,有助于集中网站权重和保证安全。
# 将非WWW域名和HTTP请求统一重定向到HTTPS+WWW域名
server {
listen 80;
server_name example.com www.example.com;
# 强制跳转到 HTTPS 的 www 域名
return 301 https://www.example.com$request_uri;
}
server {
listen 443 ssl;
server_name example.com; # 处理直接访问HTTPS非WWW的情况
ssl_certificate ...;
ssl_certificate_key ...;
return 301 https://www.example.com$request_uri;
}
server {
listen 443 ssl;
server_name www.example.com;
# 主站配置...
}
要点:使用 return 301比 rewrite ... permanent效率稍高 。
2. 实现伪静态(利于 SEO)
将动态 URL 重写为静态的、对搜索引擎友好的形式。
# 将 /product/123 重写为 /product.php?id=123
location /product/ {
rewrite ^/product/([0-9]+)$ /product.php?id=$1 last;
}
# 更复杂的博客路径重写
location /blog/ {
rewrite ^/blog/([0-9]{4})/([0-9]{2})/(.*)$ /blog/article.php?year=$1&month=$2&slug=$3 last;
}
要点:使用 last标志,让 Nginx 将重写后的 URI 作为一个新请求重新匹配 location,找到正确的处理脚本 。
3. 旧 URL 迁移与跳转
当页面路径改变时,通过 301 重定向告知用户和搜索引擎。
# 单个页面跳转
rewrite ^/old-page.html$ /new-page.html permanent;
# 整个目录跳转
rewrite ^/old-category/(.*)$ /new-category/$1 permanent;
4. 前端单页应用(SPA)路由处理
对于 Vue、React 等框架开发的应用,需要将非静态文件请求指向入口文件。
location / {
try_files $uri $uri/ /index.html;
}
要点:try_files指令会按顺序检查文件($uri)或目录($uri/)是否存在,如果都不存在,则内部重写到 /index.html。这通常比使用 rewrite更高效,是处理 SPA 路由的首选方案 。
5. 高级参数处理
使用 if和变量进行复杂的条件判断和参数操作。
# 只有当特定参数存在且值符合条件时才重写
if ($arg_city ~ "^[0-9]{1,4}$") { # 如果city参数是1-4位数字
rewrite ^/some/path$ /new/path?city_code=$arg_city? last;
}
# 处理POST请求的重定向(避免转为GET请求)
if ($request_method = POST) {
return 307 https://new.example.com$request_uri;
}
要点:return 307会保持原请求方法(如 POST)进行重定向 。$arg_后接参数名可以获取该查询字符串的值。
6. 使用 Map 优化大量重定向规则
当有成百上千条重定向规则时,使用 map指令可以提高匹配效率和可维护性。
# 在http块中定义map
map $request_uri $new_uri {
include /etc/nginx/conf.d/redirects.map;
# redirects.map 文件内容示例:
# /old-url-1 /new-url-1;
# /old-url-2 /new-url-2;
}
# 在server或location块中使用
if ($new_uri) {
rewrite ^ $new_uri permanent;
}
要点:这种方式将映射关系放在外部文件,易于管理大量规则 。
五. 最佳实践与避坑指南
-
执行顺序:Nginx 的
rewrite指令按配置顺序执行。顺序很重要! -
避免循环:重写规则设计不当可能导致 Nginx 陷入内部重写循环(超过 10 次会返回 500 错误)。
-
慎用
if:if指令在某些上下文中可能存在“坑”,尽量避免在location块中使用if进行复杂的文件存在性判断等操作 。 -
保留查询参数:在重定向时,使用
$request_uri(包含完整路径和参数)或手动附加$args变量,避免丢失原始请求的参数 。 -
正则优化:编写正则表达式时尽量精确,使用
^和$锚定边界,避免过于宽泛的匹配导致性能下降或误匹配。 -
测试与日志:修改配置后,务必使用
nginx -t测试语法。可以使用rewrite_log on;将重写过程输出到错误日志(error_log级别设为notice)以便调试 。
六. 总结
Nginx 的 rewrite模块功能强大。核心在于理解不同 flag 的差异,并根据场景(内部重写还是外部重定向)正确选择。在生产实践中,优先考虑使用 return进行简单重定向,使用 try_files处理静态资源查找和 SPA 路由,在需要进行复杂的模式匹配和替换时才使用 rewrite。
6463

被折叠的 条评论
为什么被折叠?



