Nginx rewrite规则:实现高效域名跳转的完整指南

一、域名跳转的核心需求与Nginx解决方案

在互联网业务中,域名跳转是常见的运维需求,典型场景包括:

  1. HTTP到HTTPS的安全升级(强制HTTPS)
  2. 旧域名到新域名的永久迁移(301重定向)
  3. 多域名统一入口管理(如www与非www版本合并)
  4. 测试环境与生产环境的流量切换

Nginx通过rewrite模块提供了强大的URL重写能力,其核心优势在于:

  • 高性能:基于PCRE正则表达式引擎,处理效率远超脚本语言
  • 灵活性:支持条件判断、变量捕获、标志位控制等高级功能
  • 可扩展性:可与location、if等指令组合实现复杂逻辑

1.1 rewrite指令基础语法

  1. rewrite regex replacement [flag];
  • regex:正则表达式匹配请求URI(不含域名部分)
  • replacement:替换后的URI,支持$1-$9捕获组变量
  • flag:控制重写行为的标志(break/last/redirect/permanent)

1.2 常用标志位详解

标志位 行为描述 典型应用场景
break 停止后续rewrite检查,继续当前location处理 内部路径重写
last 重新搜索匹配location,可能进入新location 跨location的重定向
redirect 返回302临时重定向(HTTP状态码) 测试环境跳转
permanent 返回301永久重定向(HTTP状态码) 域名迁移

二、典型域名跳转场景实现

2.1 HTTP到HTTPS的强制跳转

  1. server {
  2. listen 80;
  3. server_name example.com www.example.com;
  4. return 301 https://$host$request_uri;
  5. # 或使用rewrite实现(不推荐,return更高效)
  6. # rewrite ^ https://$host$request_uri permanent;
  7. }

优化建议

  • 优先使用return指令,性能比rewrite高30%
  • $host变量自动获取请求头中的Host值
  • $request_uri包含查询参数(如?id=123)

2.2 旧域名到新域名的301迁移

  1. server {
  2. listen 80;
  3. server_name old-domain.com;
  4. rewrite ^/(.*)$ https://new-domain.com/$1 permanent;
  5. }

注意事项

  • 301重定向会被浏览器缓存,测试时建议使用Chrome无痕模式
  • 迁移后需在旧域名DNS设置TTL最小值(如300秒)
  • 通过curl -I http://old-domain.com验证HTTP头是否包含301

2.3 www与非www的统一处理

  1. # 强制添加www
  2. server {
  3. listen 80;
  4. server_name example.com;
  5. rewrite ^ https://www.example.com$request_uri permanent;
  6. }
  7. # 强制去除www
  8. server {
  9. listen 80;
  10. server_name www.example.com;
  11. rewrite ^ https://example.com$request_uri permanent;
  12. }

性能优化

  • 使用map指令预处理域名,减少正则匹配开销
    1. map $host $canonical_host {
    2. default $host;
    3. ~^www\.(.+) $1;
    4. ~^([^.]+)\.$ $1;
    5. }

2.4 多域名统一入口

  1. server {
  2. listen 80;
  3. server_name example.com example.org example.net;
  4. if ($host = "example.org") {
  5. rewrite ^ https://example.com$request_uri permanent;
  6. }
  7. if ($host = "example.net") {
  8. rewrite ^ https://example.com$request_uri permanent;
  9. }
  10. # 更高效的map实现方式
  11. map $host $redirect_target {
  12. default "";
  13. example.org https://example.com;
  14. example.net https://example.com;
  15. }
  16. server {
  17. if ($redirect_target) {
  18. return 301 $redirect_target$request_uri;
  19. }
  20. }
  21. }

最佳实践

  • 避免在location块中使用if(可能产生意外行为)
  • 复杂条件判断建议使用Lua脚本(通过OpenResty)

三、高级配置技巧

3.1 正则表达式性能优化

  1. # 低效写法(包含重复匹配)
  2. rewrite ^/(user|admin)/(.*)$ /$2?role=$1 last;
  3. # 高效写法(使用非捕获组)
  4. rewrite ^/(?:user|admin)/(.*)$ /$1?role=$1 last;

优化原则

  • 优先使用^$锚点限定匹配范围
  • 避免过度复杂的嵌套正则
  • 对高频访问路径建立专用location块

3.2 变量捕获与传递

  1. # 捕获路径中的版本号
  2. rewrite ^/v([0-9]+)/api/(.*)$ /api/$2?version=$1 last;
  3. # 传递原始请求方法(用于API网关)
  4. map $request_method $custom_header {
  5. default "";
  6. POST "X-Original-Method: POST";
  7. }

3.3 条件跳转控制

  1. # 仅对移动端UA跳转
  2. map $http_user_agent $is_mobile {
  3. default 0;
  4. "~*android" 1;
  5. "~*iphone" 1;
  6. }
  7. server {
  8. if ($is_mobile) {
  9. rewrite ^ https://m.example.com$request_uri permanent;
  10. }
  11. }

替代方案

  • 使用$http_user_agent变量配合正则
  • 更复杂的UA检测建议使用Lua脚本

四、常见问题解决方案

4.1 无限重定向循环

问题现象:浏览器报错”ERR_TOO_MANY_REDIRECTS”

排查步骤

  1. 检查rewrite规则是否形成闭环(如A→B→A)
  2. 验证$host变量是否符合预期
  3. 使用curl -v查看完整重定向链

修复示例

  1. # 错误示例(导致循环)
  2. server {
  3. server_name example.com;
  4. rewrite ^ https://example.com$request_uri permanent;
  5. }
  6. # 正确写法(添加路径检查)
  7. server {
  8. server_name example.com;
  9. if ($request_uri !~ "^/new-") {
  10. rewrite ^ https://example.com/new$request_uri permanent;
  11. }
  12. }

4.2 正则表达式不匹配

调试技巧

  1. 使用nginx -t测试配置语法
  2. 在location块中添加临时日志:
    1. location / {
    2. access_log /tmp/rewrite.log;
    3. rewrite_log on;
    4. # 测试规则
    5. if ($uri ~ "^/test/(.*)") {
    6. return 200 "Matched: $1";
    7. }
    8. }
  3. 使用在线正则测试工具验证表达式

4.3 性能瓶颈分析

监控指标

  • rewrite指令执行次数(通过stub_status模块)
  • 平均重定向延迟(通过Nginx Plus或第三方监控)
  • 内存占用(正则表达式编译缓存)

优化建议

  • 将固定跳转规则升级为return指令
  • 对高频访问路径预编译正则表达式
  • 考虑使用OpenResty的Lua脚本替代复杂rewrite

五、安全加固建议

5.1 防止开放重定向漏洞

风险场景

  • 用户可控参数直接拼接到重定向URL
  • 未验证目标域名是否属于白名单

防护方案

  1. # 严格限制重定向域名
  2. map $arg_url $safe_redirect {
  3. default "";
  4. ~*^https?://(www\.)?example\.com(/.*)?$ $arg_url;
  5. }
  6. server {
  7. if ($safe_redirect) {
  8. return 301 $safe_redirect;
  9. }
  10. }

5.2 HSTS头配置

  1. server {
  2. listen 443 ssl;
  3. add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
  4. # 其他配置...
  5. }

5.3 日志与监控

  1. http {
  2. log_format rewrite_log '$remote_addr - $host $request '
  3. '"$status" "$upstream_addr" '
  4. '"$request_time" "$upstream_response_time"';
  5. access_log /var/log/nginx/rewrite.log rewrite_log;
  6. }

六、总结与最佳实践

  1. 性能优先:简单跳转使用return,复杂逻辑用rewrite
  2. 安全第一:严格校验重定向目标,防止开放重定向
  3. 可维护性
    • 为重要跳转规则添加注释
    • 使用include指令拆分配置
    • 建立变更记录文档
  4. 监控体系
    • 跟踪301/302响应码比例
    • 监控重定向延迟
    • 设置异常跳转告警

推荐配置结构

  1. nginx.conf
  2. ├── includes/
  3. ├── redirects-common.conf # 通用变量定义
  4. ├── redirects-http.conf # HTTP到HTTPS跳转
  5. └── redirects-domain.conf # 域名迁移规则
  6. └── conf.d/
  7. └── example.com.conf # 站点特定配置

通过系统化的rewrite配置管理,企业可以:

  • 降低SEO负面影响(正确使用301/302)
  • 提升用户体验(减少重定向次数)
  • 增强安全性(防止URL跳转攻击)
  • 简化运维(集中管理跳转规则)

建议每季度审核一次重定向规则,清理无效跳转,确保配置始终与业务需求保持同步。