Nginx 学习笔记:URL Rewrite 从入门到实战,让链接更优雅、更SEO友好


📝 本文首发于 栏轩·阁

欢迎访问阅读原文,获取更好的阅读体验。


一、URL Rewrite 是什么?为什么需要它?

URL Rewrite(URL 重写)是 Nginx 的核心功能之一,它允许你在请求到达服务器时,动态地修改请求的 URL,而不改变用户浏览器地址栏中显示的链接(或者根据需要改变)。

核心价值

  • SEO 优化 :将 ?page=2&id=123 这样的动态参数 URL 转换为 /page/2/id/123.html 的静态化 URL,搜索引擎更喜欢后者
  • 用户体验:简洁、有语义的 URL 更容易被用户理解和记忆
  • 安全:隐藏真实的请求参数和目录结构,避免暴露技术细节
  • 兼容性:网站改版时,将旧链接 301 重定向到新链接,保证 SEO 权重不丢失

二、一个典型场景:动态页面伪装成静态 HTML

需求

原始页面:/good?page=2

希望用户访问:/good/2.html 就能看到同样的内容

这样做的好处:

  • 隐藏真实参数 :不暴露 ?page= 这样的查询字符串
  • 伪装成静态 HTML:搜索引擎和用户都更偏好静态化的 URL
  • 更利于 SEO:搜索引擎对静态 URL 的索引和排名更友好

完整配置实现

nginx 复制代码
server {
    listen 80;
    server_name example.com;

    # 用户访问 /good/2.html 时,内部重写为 /good?page=2
    location / {
        rewrite ^/good/(\d+)\.html$ /good?page=$1 last;
    }

    # 实际处理请求的 location
    location /good {
        # 这里是正常的业务逻辑
        proxy_pass http://backend;
        # 或者 try_files 等
    }
}

配置逐行解析

配置 说明
rewrite Nginx 重写指令
^/good/(\d+)\.html$ 正则表达式 :匹配类似 /good/2.html 的链接,(\d+) 捕获数字部分
/good?page=$1 替换后的 URL :$1 引用第一个捕获的分组(即数字 2)
last flag 标记:表示完成重写后,用新 URL 重新匹配 location

三、Rewrite 统一语法

基本语法

nginx 复制代码
rewrite regex replacement [flag];
部分 说明
regex 正则表达式,匹配用户请求的 URI
replacement 替换后的 URI,可以引用正则捕获的变量($1、$2 等)
flag 可选,控制重写后的行为方式

Rewrite 指令的作用位置

rewrite 可以出现在以下两个上下文中:

  1. server 块 --- 在 server 级别对所有请求生效
  2. location 块 --- 仅对匹配该 location 的请求生效
  3. if 块 --- 结合条件判断使用
nginx 复制代码
# 在 server 块中全局生效
server {
    rewrite ^/old-path/(.*)$ /new-path/$1 permanent;
}

# 在 location 块中对特定路径生效
location /images {
    rewrite ^/images/(.*)$ /assets/$1 break;
}

四、四大 Flag 标记详解

Flag 是 rewrite 指令的关键部分,决定了重写后 Nginx 的行为方式。

Flag 行为 适用场景 是否改变浏览器 URL
last 重写后重新搜索 location 匹配 在 location 块中使用,需要重新匹配时 ❌ 内部重写
break 重写后停止 rewrite 模块的处理,但不重新匹配 location 当前 location 已经匹配正确,只需重写 URI 即可 ❌ 内部重写
redirect 返回 302 临时重定向 临时性的 URL 变更 ✅ 浏览器地址变化
permanent 返回 301 永久重定向 永久性的 URL 变更、网站改版 ✅ 浏览器地址变化

如何选择?一张图看懂

复制代码
用户请求 URL
    │
    ▼
rewrite 匹配成功
    │
    ├── flag = last      → 用新 URI 重新匹配 location(内部跳转,URL 不变)
    ├── flag = break     → 用新 URI 继续当前请求(不重新匹配,URL 不变)
    ├── flag = redirect  → 返回 302,告诉浏览器换地址(URL 会变)
    └── flag = permanent → 返回 301,永久迁移(URL 会变,搜索引擎更新索引)

示例:last vs break 的区别

nginx 复制代码
location /a/ {
    rewrite ^/a/(.*)$ /b/$1 last;
}

location /b/ {
    rewrite ^/b/(.*)$ /c/$1 last;
}

请求 /a/foo → 第一次 rewrite 为 /b/foo,last 触发重新匹配 → 进入 location /b/ → 第二次 rewrite 为 /c/foo

如果用 break 替换上面的 last:

  • 请求 /a/foo → rewrite 为 /b/foo,但 break 不重新匹配 → 直接处理 /b/foo,不会 执行 location /b/ 中的 rewrite

301 vs 302 的选择

场景 推荐
网站永久迁移到新域名 permanent(301)
旧链接永久更换为新格式 permanent(301)
临时维护页面 redirect(302)
A/B 测试流量分发 redirect(302)
不确定是否永久改动 redirect(302)

六、实战案例详解

案例 1:文章 ID 美化

需求 :/article.php?id=123 → /article/123.html

nginx 复制代码
location / {
    rewrite ^/article/(\d+)\.html$ /article.php?id=$1 last;
}

案例 2:多参数传递

需求 :/list?cat=tech&page=2 → /list/tech/2.html

nginx 复制代码
location / {
    rewrite ^/list/(\w+)/(\d+)\.html$ /list?cat=$1&page=$2 last;
}

案例 3:分类+文章名(WordPress 风格)

需求 :/post?slug=hello-world → /2024/01/hello-world.html

nginx 复制代码
location / {
    rewrite ^/(\d{4})/(\d{2})/([\w-]+)\.html$ /post?year=$1&month=$2&slug=$3 last;
}

案例 4:域名跳转(301 永久重定向)

需求 :旧域名 old-site.com 全部跳转到 new-site.com

nginx 复制代码
server {
    listen 80;
    server_name old-site.com www.old-site.com;

    rewrite ^(.*)$ http://new-site.com$1 permanent;
}

# 更推荐用 return 301,性能更好:
server {
    listen 80;
    server_name old-site.com www.old-site.com;
    return 301 http://new-site.com$request_uri;
}

案例 5:强制 HTTPS

nginx 复制代码
server {
    listen 80;
    server_name example.com;

    rewrite ^(.*)$ https://$host$1 permanent;
    # 或用 return(更高效):
    # return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name example.com;
    # 正常的 HTTPS 配置
}

五、常见问题与注意事项

1. Rewrite 与 Return 的选择

return 比 rewrite 性能更好 ,因为它直接中断请求处理,不经过正则匹配。能用 return 的场景优先用 return:

nginx 复制代码
# ✅ 推荐:return 301
return 301 https://$host$request_uri;

# ❌ 不推荐:rewrite ... permanent
rewrite ^(.*)$ https://$host$1 permanent;

2. 注意死循环

nginx 复制代码
# ❌ 错误示例:会陷入无限循环
location / {
    rewrite ^/article/(\d+)$ /article/$1 last;
}

因为 rewrite 后重新匹配 location,又匹配到 / 这个 location,再次触发 rewrite。

解决方法 :使用 break 或将具体规则放在更精确的 location 中。

3. Proxy_Pass 下的 Rewrite 顺序

当同时使用 proxy_pass 和 rewrite 时,rewrite 在 proxy_pass 之前执行。可以先在 location 中 rewrite 修改 URI,再 proxy_pass 转发。

举个例子,有个后端接口接收 /api/user?id=123,但你想让用户访问 /user/123 就能调用它:

nginx 复制代码
location / {
    rewrite ^/user/(\d+)$ /api/user?id=$1 break;
    proxy_pass http://backend_server;
}

执行流程:

  1. 用户访问 /user/123
  2. rewrite 先把 URI 改为 /api/user?id=123
  3. 然后 proxy_pass 将修改后的请求转发给后端

再看一个实际场景:前端静态资源和后端 API 混用:

nginx 复制代码
server {
    listen 80;
    server_name blog.example.com;

    location / {
        # 先尝试读取静态文件,没有命中才 rewrite
        root /var/www/static;
    }

    location /api/ {
        # 把 /api/article/42 重写为 /index.php?route=article&id=42
        rewrite ^/api/(\w+)/(\d+)$ /index.php?route=$1&id=$2 break;
        proxy_pass http://php_backend:9000;
    }
}

访问 /api/article/42 时:

  • rewrite 先将路径重写为 /index.php?route=article&id=42
  • 然后 proxy_pass 将重写后的请求转发给 PHP 后端处理

4. 调试 Rewrite 规则

启用 rewrite 日志,方便调试:

nginx 复制代码
server {
    # 开启 rewrite 日志
    rewrite_log on;
    error_log /var/log/nginx/rewrite_error.log notice;
}

在错误日志中可以看到每个 rewrite 的执行步骤,非常有助于排查问题。


六、总结

关键点 要点
语法 rewrite regex replacement [flag]
四个 flag last(重匹配)、break(停止)、redirect(302)、permanent(301)
正则捕获 () 捕获,$1、$2 引用
性能 单纯的重定向用 return 而不是 rewrite
调试 开启 rewrite_log on 查看重写过程
SEO 301 传递权重,302 不传递,按场景选择

URL Rewrite 是 Nginx 配置中最常用也最强大的功能之一,掌握了它,你就能随心所欲地控制网站的 URL 结构,让链接既美观又对搜索引擎友好。

相关推荐
吴声子夜歌1 小时前
Nginx应用与运维——Nginx Web服务应用实战(HTTPS安全服务器的搭建)
运维·前端·nginx
吴声子夜歌2 小时前
Nginx应用与运维——Nginx Web服务应用实战(伪流媒体服务器的搭建)
运维·前端·nginx
吴声子夜歌2 小时前
Nginx应用与运维——Nginx Web服务应用实战(HTTP增强协议服务器的搭建)
运维·前端·nginx
天衍四九-16 小时前
【无标题】
前端·spring boot·mysql·nginx·docker
吴声子夜歌20 小时前
Nginx应用与运维——Nginx HTTP模块详解(动态赋值功能模块)
运维·nginx·http
姜鱼问生20 小时前
三层防火墙排查:Nginx 配好了浏览器还打不开
nginx·安全
小白的码BUG之路1 天前
Docker -- 构建nginx镜像,启动vue项目
vue.js·nginx·docker
yume_sibai1 天前
04-Nginx部署实战完全指南(前端部署 + 后端代理 + 监控告警 + 故障排查)
运维·前端·nginx
程序员清风1 天前
Docker、Nginx 与 Kubernetes 部署 AI 后端服务
nginx·docker·kubernetes