第一次接触Nginx的rewrite功能时,我正面临一个典型的URL规范化问题。当时我们的电商网站同时存在带www和不带www的访问方式,导致搜索引擎重复收录。rewrite规则只用三行配置就解决了这个困扰团队两周的难题:
nginx复制server {
listen 80;
server_name example.com;
return 301 $scheme://www.example.com$request_uri;
}
这个经历让我意识到rewrite是Nginx最强大的武器之一。它本质上是一个URL转换引擎,通过正则表达式匹配和变量操作,实现请求路径的动态改写。不同于简单的重定向,rewrite能在请求处理流程中实时修改URI,而不需要客户端二次请求。
rewrite指令的标准语法如下:
nginx复制rewrite regex replacement [flag];
关键点在于flag参数,它决定了重写行为的处理方式:
经验:生产环境务必使用permanent而非redirect,避免搜索引擎重复索引。我曾因误用redirect导致网站排名波动两周。
Nginx使用PCRE正则引擎,支持捕获组和命名捕获。这里有个实际案例:我们需要将旧版URL /product/123 迁移到新版 /goods/123:
nginx复制rewrite ^/product/(\d+)$ /goods/$1 permanent;
高级技巧:
(?P<name>pattern)命名捕获组,提高可读性.*匹配会吞掉后续路径,建议用[^/]*替代return 200 "match:$1";验证匹配结果这是最常见的需求配置模板:
nginx复制server {
listen 80;
server_name
example.com
www.example.com
example.net
www.example.net;
if ($host != 'www.example.com') {
rewrite ^(.*)$ $scheme://www.example.com$1 permanent;
}
# 主站点配置...
}
内容管理系统常需要将动态参数转化为静态路径。比如将/index.php?page=about显示为/about/:
nginx复制location / {
try_files $uri $uri/ @rewrite;
}
location @rewrite {
rewrite ^/([^/]+)/?$ /index.php?page=$1 last;
}
单页应用(SPA)需要将所有非静态资源请求转发到index.html:
nginx复制location / {
try_files $uri $uri/ /index.html;
# 处理带参数的静态资源
rewrite ^/static/(.*)\?(.*)$ /static/$1 last;
}
通过rewrite_log on;开启调试日志后,我总结出这些性能规律:
实测案例:将rewrite ^/category/(.*)/(.*)$优化为rewrite ^/category/([^/]+)/([^/]+)$后,QPS从1200提升到2100。
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 循环重定向 | last标志缺失 | 检查rewrite终点是否匹配location |
| 500错误 | 替换字符串语法错误 | 用echo指令测试变量值 |
| 规则不生效 | 执行顺序问题 | 调整rewrite位置到server层级 |
| 特殊字符失效 | 未转义正则元字符 | 对. *等字符使用反斜杠转义 |
对于复杂路由逻辑,可以先用map预处理:
nginx复制map $uri $new_uri {
default "";
"/old/path" "/new/path";
"~^/user/(\d+)" "/member/$1";
}
server {
if ($new_uri) {
rewrite ^ $new_uri permanent;
}
}
通过变量实现动态路由:
nginx复制set $test_group "A";
if ($http_cookie ~* "test_group=B") {
set $test_group "B";
}
location /promo {
rewrite ^/promo(.*)$ /v$test_group/promo$1 last;
}
按用户特征分流请求:
nginx复制geo $gray_user {
default 0;
10.0.0.0/8 1;
192.168.1.100 1;
}
server {
if ($gray_user) {
rewrite ^/(.*)$ /gray/$1 break;
}
location /gray {
proxy_pass http://gray_upstream;
}
}
在实施rewrite规则时,我习惯先用curl -I测试响应头,再用nginx -T验证配置完整性。记住:永远在修改前备份nginx.conf,有次误操作导致线上500错误后,我现在每次改动前都会执行cp nginx.conf{,.bak}