Nginx 中的 rewrite 和 redirect 有什么区别?
在 Nginx(以及一般的 Web 服务器)中,Rewrite(内部重写) 和 Redirect(外部重定向) 是两个经常被混淆的概念。
简单来说,它们的核心区别在于:谁来完成地址的转换?
- Rewrite(重写) 是服务器内部的行为。
- Redirect(重定向) 是客户端(浏览器)的行为。
需要特别说明的是,在 Nginx 的配置文件中,rewrite 是一个具体的指令,而这个指令根据后面跟的 flag(标志位)不同,既可以实现内部重写,也可以实现外部重定向。
以下是两者的详细区别:
1. Rewrite(内部重写)
工作原理:
当客户端请求一个 URL 时,Nginx 在服务器内部将这个 URL 修改为另一个 URL,然后直接去获取修改后的 URL 对应的内容,并把内容返回给客户端。整个过程客户端完全不知道,浏览器地址栏的 URL 不会发生变化。
- HTTP 状态码: 通常返回
200 OK。 - 网络开销: 只有一次请求和一次响应,效率高。
- 应用场景:
- 伪静态(Clean URLs): 将动态的、带有复杂参数的 URL(如
/article.php?id=123)伪装成友好的 URL(如/article/123)。 - 隐藏真实目录结构: 提高网站安全性,不暴露后端真实代码路径。
- 单页应用(SPA)路由: 将所有请求都指向
index.html(前端路由)。
- 伪静态(Clean URLs): 将动态的、带有复杂参数的 URL(如
- Nginx 指令实现: 使用
rewrite指令,并配合last或break标志位。
Nginx 配置示例:
plaintext
# 浏览器请求 /article/123
# Nginx 内部去读取 /article.php?id=123 的内容返回,浏览器地址栏依然是 /article/123
rewrite ^/article/([0-9]+)$ /article.php?id=$1 last;
2. Redirect(外部重定向)
工作原理:
当客户端请求一个 URL 时,Nginx 服务器告诉客户端(浏览器):“你要找的内容不在这里,请去另一个地址找”。服务器会返回一个 30x 的状态码和一个 Location 响应头,浏览器收到后,会自动发起一个新的请求到目标 URL,浏览器地址栏的 URL 会发生变化。
- HTTP 状态码:
301 Moved Permanently(永久重定向) 或302 Found(临时重定向)。 - 网络开销: 需要客户端发起两次请求,增加了网络延迟。
- 应用场景:
- 域名变更: 旧域名无缝跳转到新域名。
- HTTP 强制跳转 HTTPS: 保证数据传输安全。
- SEO 优化: 将多个相似的 URL 权重集中到一个 URL 上(使用 301)。
- 页面已废弃: 旧页面下线,引导用户访问新的替代页面。
- Nginx 指令实现: 使用
return 30x指令(推荐),或者使用rewrite指令配合redirect(302)或permanent(301)标志位。
Nginx 配置示例:
plaintext
# 推荐做法:使用 return (性能更好)
# 浏览器请求 http://old-domain.com,浏览器地址栏会变成 https://new-domain.com
server {
listen 80;
server_name old-domain.com;
return 301 https://new-domain.com$request_uri;
}
# 也可以用 rewrite 指令实现 (permanent = 301, redirect = 302)
rewrite ^/old-page$ /new-page permanent;
核心区别对比总结表
| 比较维度 | Rewrite (内部重写) | Redirect (外部重定向) |
|---|---|---|
| 发生位置 | 服务器内部 | 客户端(浏览器) |
| 浏览器地址栏 URL | 不变 | 改变(变成新的 URL) |
| 请求次数 | 1 次(客户端只发一次请求) | 2 次(客户端收到 30x 后再发一次请求) |
| HTTP 状态码 | 200 (通常) | 301, 302, 307, 308 等 |
| 执行速度 | 快(无额外网络开销) | 相对较慢(多了一次往返网络请求) |
| SEO 影响 | 搜索引擎收录原始 URL | 301 会将权重转移到新 URL |
| Nginx 常用标志 | last, break |
return 301/302, permanent, redirect |
最佳实践建议
- 如果需要改变浏览器地址栏,或者做域名/协议转换(HTTP 到 HTTPS),请使用 Redirect(优先使用 Nginx 的
return指令,因为它的执行效率比处理正则表达式的rewrite更高)。 - 如果是为了美化 URL、隐藏后端真实路径,且不想让用户察觉,请使用 Rewrite(使用
rewrite ... last;或rewrite ... break;)。