Nginx学习笔记(九)—— Nginx Rewrite深度解析
🔀🔀 Nginx Rewrite深度解析
📌📌 一、Rewrite核心价值与原理
✅ 核心作用:
- 🔧 URL美化:将复杂动态URL转为静态友好地址
- 🔀 路径校正:自动补全缺失斜杠或修正大小写
- 🚚 流量调度:根据条件路由到不同后端服务
- 🔒 安全加固:隐藏敏感路径参数
- 📶 访问控制:基于规则拒绝恶意请求
⚙⚙⚙️ 二、Rewrite配置语法
基础指令结构:
rewrite regex replacement [flag];
核心参数解析:
参数 | 必需 | 描述 |
---|---|---|
regex | ✅ | Perl兼容正则表达式 |
replacement | ✅ | 替换后的目标字符串 |
flag | ❌ | 控制重写行为(详见下表) |
标志位详解:
Flag | 作用 | 执行特点 |
---|---|---|
last | 终止当前location重写 | 用新URI重新搜索location |
break | 终止所有重写 | 在当前location继续执行 |
redirect | 302临时重定向 | 浏览器地址栏变化 |
permanent | 301永久重定向 | 浏览器缓存重定向 |
🔧🔧🔧 三、核心指令详解
1️⃣ rewrite
指令
location /blog/ {# 将 /blog/123 → /posts?id=123rewrite ^/blog/(\d+)$ /posts?id=$1 last;
}
2️⃣ if
条件判断
# 语法:if (condition) { ... }
location / {# 移动设备重定向if ($http_user_agent ~* "mobile|android") {rewrite ^(.*)$ /mobile$1 last;}# 非法IP拦截if ($remote_addr = "202.96.134.33") {return 403;}
}
条件运算符:
=
: 字符串相等!=
: 字符串不等~
: 正则匹配(区分大小写)~*
: 正则匹配(不区分大小写)-f
: 文件存在-d
: 目录存在
3️⃣ set
变量设置
location / {set $site_version "v2";# 根据时间设置版本if ($time_hour > 18) {set $site_version "nightly";}rewrite ^/(.*)$ /$site_version/$1;
}
4️⃣ break
与return
控制流
location /api/ {# 终止重写链rewrite ^/api/v1/(.*)$ /legacy/$1 break;rewrite ^/api/v2/(.*)$ /new/$1 break;# 直接返回响应return 200 "API Endpoint";
}
🔄🔄🔄 四、实战配置案例
🌐 案例1:域名标准化
server {listen 80;server_name example.com www.example.com;# 统一主域名if ($host != 'example.com') {rewrite ^(.*)$ https://example.com$1 permanent;}# HTTP转HTTPSif ($scheme = http) {rewrite ^(.*)$ https://$host$1 permanent;}
}
📁 案例2:路径重写
location /ecommerce {# 智能路径重写rewrite ^/ecommerce/product-(\d+)$ /products/$1 last;rewrite ^/ecommerce/category-(.*)$ /categories/$1 last;rewrite ^/ecommerce/(.*)$ /shop/$1 last;
}
🛡 案例3:防盗链实现
location ~* \.(jpg|png|gif)$ {# 允许空Referer和自身域名valid_referers none blocked server_names *.example.com;# 非法引用重写到水印图if ($invalid_referer) {rewrite ^(.*)$ /watermark$1 break;}
}
🔀 案例4:多级路径合并
location /archive {# /archive/2023/05/01 → /posts?date=2023-05-01rewrite ^/archive/(\d+)/(\d+)/(\d+)$ /posts?date=$1-$2-$3 last;# /archive/cat/tech → /category?name=techrewrite ^/archive/cat/(\w+)$ /category?name=$1 last;
}
📊📊 五、全局变量应用
常用内置变量:
变量 | 描述 | 应用场景 |
---|---|---|
$args | 请求参数 | 保留原始参数 |
$request_uri | 完整原始URI | 带参数的完整重定向 |
$scheme | 协议类型 | HTTP/HTTPS转换 |
$http_user_agent | 浏览器UA | 设备适配 |
$http_referer | 来源页面 | 防盗链检测 |
$remote_addr | 客户端IP | 访问控制 |
高级变量应用:
location /analytics {# 带参数重定向:/analytics?page=home → /stats/homeif ($args ~* "page=(.*)") {set $page $1;rewrite ^ /stats/$page? last;}# 保留原始参数:/search?q=nginx → /v2/search?q=nginxrewrite ^/search(.*)$ /v2/search$1?$args last;
}
⚠⚠⚠️ 六、高阶技巧与陷阱规避
🔧 技巧1:递归重写控制
location /download {# 最多递归10次rewrite_by_depth 10;# 文件版本清理rewrite "^/(.*)-v\d+\.(.*)$" /$1.$2 last;
}
🎭 技巧2:动态重写映射
# 创建重写映射表
map $uri $new_uri {default "";~^/old-blog/(.*) /new-blog/$1;~^/shop/(.*) /ecommerce/$1;
}server {location / {if ($new_uri) {rewrite ^ $new_uri last;}}
}
📶 技巧3:AB测试路由
split_clients $request_uri $variant {50% "groupA";50% "groupB";
}location / {rewrite ^/(.*)$ /$variant/$1 last;
}
❌ 常见陷阱解决方案:
- 循环重定向问题
# 添加终止条件
location / {if ($request_uri ~ "^/(.*)/$") {set $has_slash on;}if ($has_slash != on) {rewrite ^(.*)$ $1/ permanent;}
}
- 正则性能优化
# 优化前(低效)
rewrite ^/([0-9]{4})/([0-9]{2})/([0-9]{2})/(.*)$ /archive/$1$2$3/$4;# 优化后(高效)
rewrite ^/(\d{4})/(\d{2})/(\d{2})/(.+)$ /archive/$1$2$3/$4 last;
- 变量未定义错误
# 安全访问变量
if ($arg_id = "") {set $arg_id "default";
}
rewrite ^/(.*)$ /item/$arg_id last;
📊📊 七、调试与监控方案
专用日志格式:
log_format rewrite_log '$remote_addr - $request_uri ''-> $uri [$status] ''"$http_user_agent"';server {rewrite_log on; # 启用重写日志error_log /var/log/nginx/rewrite.log notice;location / {access_log /var/log/nginx/rewrite_access.log rewrite_log;}
}
诊断命令集:
# 实时跟踪重写流程
tail -f /var/log/nginx/rewrite.log# 测试重写规则
curl -I http://example.com/test-path# 重写规则语法检查
nginx -t
性能监控:
# 统计重写次数
grep -c "rewritten" /var/log/nginx/rewrite.log# 查找最耗时的重写
awk '/rewrite_log/ {print $NF,$7}' access.log | sort -nr