nginx rewrite
- nginx documentation https://nginx.org/en/docs/
- ngx_http_rewrite_module https://nginx.org/en/docs/http/ngx_http_rewrite_module.html 下面是补全的 Nginx 配置示例,其中包括了路径重写和将 HTTP 流量重定向到 HTTPS 的配置。这些示例都有相应的注释来帮助理解每一条指令的作用。
1. URL 重写路径
这个例子展示了如何将某个特定的请求路径重写到另一个路径。比如将所有 /old-path
的访问重写到 /new-path
。
server {
listen 80;
server_name example.com;
# 重写路径示例:将 /old-path 重定向到 /new-path
location /old-path {
rewrite ^/old-path(.*)$ /new-path$1 last;
}
# 其他位置定义
location / {
try_files $uri $uri/ =404;
}
}
2. HTTP 重写 HTTPS
这个例子展示了如何把通过 HTTP (端口 80) 访问的流量重定向到 HTTPS (端口 443)。这是一种常用的方法,用于提升网站的安全性。
server {
listen 80;
server_name example.com;
# 重定向所有 HTTP 流量到 HTTPS
# 捕获所有请求并使用 301 永久重定向到相同的域名上的 HTTPS 协议
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# SSL 配置细节可能根据实际情况有所不同
# 其他安全相关的 SSL 配置如下
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'HIGH:!aNULL:!MD5';
# HTTPS 下的内容处理
location / {
try_files $uri $uri/ =404;
}
}
以上配置文件中:
- 第一个
server
块监听 80 端口并定义了将所有 HTTP 流量重定向到 HTTPS 的规则。 - 第二个
server
块监听 443 端口,为 HTTPS 流量提供服务,并包含了 SSL 证书和密钥的路径以及其他 SSL 安全设置。
通过这些设置,可以确保网站的流量通过安全的 HTTPS 协议传输。
3. 基于 User-Agent 重定向 - pc 和移动端两套代码,分别由 pc 和 mobile 两个目录
要基于 User-Agent 实现对 PC 和移动端用户的重定向,可以在 Nginx 配置中使用 if
指令来检测 User-Agent 字符串,并根据其值来重定向用户到不同的目录。下面是一个实现这一功能的 Nginx 配置示例:
server {
listen 80;
server_name example.com;
# 根据 User-Agent 重定向到 PC 或移动端代码
# 检查 User-Agent 是否包含移动设备的典型标识符
if ($http_user_agent ~* '(mobile|webos|iphone|ipad|android)') {
# 如果是移动设备,重定向到 mobile 目录
rewrite ^(.*)$ /mobile$1 break;
}
if ($http_user_agent !~* '(mobile|webos|iphone|ipad|android)') {
# 如果是 PC 设备,重定向到 pc 目录
rewrite ^(.*)$ /pc$1 break;
}
# 具体文件处理 - PC 版本
location /pc {
alias /path/to/root/pc;
try_files $uri $uri/ =404;
}
# 具体文件处理 - 移动版
location /mobile {
alias /path/to/root/mobile;
try_files $uri $uri/ =404;
}
}
在这个配置中:
- 服务器监听 80 端口,并处理对
example.com
的请求。 - 第一个
if
指令块检查User-Agent
是否包含特定的移动设备标识符。如果是移动设备,则请求会被重写到/mobile
目录。 - 第二个
if
指令块检查User-Agent
是否不包含这些移动设备标识符,如果是 PC 设备,则请求会被重写到/pc
目录。 - 每个
location
块指定如何处理到达/pc
或/mobile
的请求。这里使用了alias
指令来指定物理存储位置,try_files
指令确保文件存在,否则返回 404 错误。
注意:虽然在 Nginx 配置中使用 if
语句是可以的,但通常建议尽量避免使用多个 if
语句,因为它们可能会使配置变得复杂且难以维护。在可能的情况下,考虑使用其他 HTTP 层面的重定向方法,例如在客户端使用 JavaScript 来处理或者在服务器端应用框架内处理。
4. return 301 https://$server_name$request_uri;
与rewrite ^(.*)$ https://$server_name$1 permanent;
区别
在 Nginx 配置中,return
和 rewrite
指令都可以用来重定向请求,但它们在行为和语法上有一些关键的区别:
1. 使用 return
指令
return 301 https://$server_name$request_uri;
这行代码通过 return
指令直接返回一个 301 永久重定向响应。这是一个非常高效且直接的方法来进行重定向,因为它立即终止当前请求并发回指定的响应。
2. 使用 rewrite
指令
rewrite ^(.*)$ https://$server_name$1 permanent;
^(.*)$
:这是一个正则表达式,其中^
表示行的开始,(.*)
表示匹配任何字符(除了换行符)出现任何次数,$
表示行的结束。$1
:表示由正则表达式^(.*)$
捕获的整个请求路径,但不包括域名和协议部分。permanent
:指示这是一个永久重定向,相当于 HTTP 状态码 301。
这行代码利用 rewrite
指令和正则表达式 ^(.*)$
来实现对所有请求的重定向,其中 $1
代表由正则表达式捕获的整个请求路径。rewrite
不仅用于重定向,还可以用来修改请求的 URI,并继续处理更新后的请求,这意味着它会再次遍历 location 块以查找匹配。
3. 主要区别
- 性能:
return
指令比rewrite
指令更加高效,因为return
直接结束请求,而rewrite
则可能导致请求再次被处理流程处理。尽管在重定向场景中这种差别通常可以忽略不计,但return
通常更适用于简单重定向。 - 适用性:
return
适用于简单的、固定的重定向操作,执行直接,语法简单。rewrite
在需要对 URL 进行复杂修改或基于条件进行决策时提供更多灵活性。
4. 最佳实践
对于简单的从 HTTP 到 HTTPS 的重定向,推荐使用 return
指令,因为它简单、高效,且足以满足需求。
如果需要在重定向前对 URL 进行复杂的修改或条件判断,那么 rewrite
指令则更为合适。
在实际应用中,你可以根据具体的需求和场景选择最合适的指令。
对于大多数标准的 HTTP 到 HTTPS 的重定向,return
是首选方法。
如果需要复杂的 URI 处理逻辑,例如根据请求路径中的特定模式选择不同的重定向目标,则应使用 rewrite
。
5. 使用 rewrite 和 break 进行请求路径的条件重写
这是一个关于使用 rewrite
指令进行 break
的 Nginx 配置示例。
这个示例展示了如何在特定条件下,根据请求的 URI 结构来重写请求,并使用 break
指示符结束重写规则的进一步处理。这里的例子是将所有访问 /api/old
的请求重写到 /api/new
。
server {
listen 80;
server_name example.com;
# 根据请求路径重写并使用 break 结束处理
location /api/old {
rewrite ^/api/old/(.*)$ /api/new/$1 break;
proxy_pass http://backend-server;
}
# 其他位置定义
location / {
try_files $uri $uri/ =404;
}
}
在这个配置中:
- 服务器监听 80 端口,并处理对
example.com
的请求。 rewrite ^/api/old/(.*)$ /api/new/$1 break;
这一行定义了一个rewrite
规则,其中^/api/old/(.*)$
是一个正则表达式,用于匹配以/api/old/
开头的所有请求,并捕获后续的 URI 部分。$1
用于在新的 URI/api/new/$1
中插入这部分。- 使用
break
指示符来指出在应用了这条rewrite
规则后,应终止当前的重写级别处理,不再继续检查后续的rewrite
规则。 proxy_pass http://backend-server;
行表示所有经过重写的请求都将被转发到后端服务器。
通过这种配置,你可以根据需要灵活地调整重写逻辑,确保请求按预期重定向到正确的目的地。这样的配置在处理 API 版本迁移或路径更改时尤其有用。
转换重写规则
- documentation https://nginx.org/en/docs/
- Converting rewrite rules https://nginx.org/en/docs/http/converting_rewrite_rules.html
翻译后的文本如下:
重定向到主站点
在共享主机环境中习惯于只使用 Apache 的 .htaccess 文件来配置一切的人通常会将以下规则:
RewriteCond %{HTTP_HOST} example.org
RewriteRule (.*) http://www.example.org$1
转换成类似这样的内容:
# 主服务器块,用于重定向请求
server {
listen 80; # 监听端口80
server_name www.example.org example.org; # 处理这两个域名的请求
# 如果请求的主机头是example.org,则进行重写
if ($http_host = example.org) {
rewrite (.*) http://www.example.org$1; # 重写URL,添加www前缀
}
# 其他配置...
}
这是一种错误的、繁琐的和低效的方式。正确的方法是为 example.org 定义一个单独的服务器:
# 为example.org定义单独的服务器块
server {
listen 80; # 监听端口80
server_name example.org; # 仅处理example.org的请求
return 301 http://www.example.org$request_uri; # 永久重定向到www.example.org
}
# 为www.example.org定义服务器块
server {
listen 80; # 监听端口80
server_name www.example.org; # 仅处理www.example.org的请求
# 其他配置...
}
在 0.9.1 之前的版本中,重定向可以这样实现:
# 在较早的nginx版本中,使用rewrite进行重定向
rewrite ^ http://www.example.org$request_uri?;
另一个例子。与其使用“不是 example.com 且不是 www.example.com”的“颠倒”逻辑:
RewriteCond %{HTTP_HOST} !example.com
RewriteCond %{HTTP_HOST} !www.example.com
RewriteRule (.*) http://www.example.com$1
不如简单地定义 example.com、www.example.com 和“其他所有”:
# 定义处理example.com和www.example.com的服务器块
server {
listen 80; # 监听端口80
server_name example.com www.example.com; # 处理这两个域名的请求
# 其他配置...
}
# 定义默认服务器块,捕获所有其他未指定的域名请求
server {
listen 80 default_server; # 设置为默认服务器
server_name _; # 使用下划线作为通配符,捕获所有其他域名
return 301 http://example.com$request_uri; # 永久重定向到example.com
}
在 0.9.1 之前的版本中,重定向可以这样实现:
# 在较早的nginx版本中,使用rewrite进行重定向
rewrite ^ http://example.com$request_uri?;
转换 Mongrel 规则 典型的 Mongrel 规则:
DocumentRoot /var/www/myapp.com/current/public
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ %{DOCUMENT_ROOT}/system/maintenance.html [L]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*)$ $1 [QSA,L]
RewriteCond %{REQUEST_FILENAME}/index.html -f
RewriteRule ^(.*)$ $1/index.html [QSA,L]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.*)$ $1.html [QSA,L]
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]
应该转换为:
# 转换Mongrel规则的location块
location / {
root /var/www/myapp.com/current/public; # 设置根目录
# 尝试按顺序找到这些文件或目录,若不存在则进入@mongrel处理
try_files /system/maintenance.html $uri $uri/index.html $uri.html @mongrel;
}
# 处理@mongrel的location块
location @mongrel {
proxy_pass http://mongrel; # 使用代理传递请求到mongrel
}