Skip to content

nginx rewrite

  1. nginx documentation https://nginx.org/en/docs/
  2. ngx_http_rewrite_module https://nginx.org/en/docs/http/ngx_http_rewrite_module.html 下面是补全的 Nginx 配置示例,其中包括了路径重写和将 HTTP 流量重定向到 HTTPS 的配置。这些示例都有相应的注释来帮助理解每一条指令的作用。

1. URL 重写路径

这个例子展示了如何将某个特定的请求路径重写到另一个路径。比如将所有 /old-path 的访问重写到 /new-path

nginx
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)。这是一种常用的方法,用于提升网站的安全性。

nginx
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 配置示例:

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 配置中,returnrewrite 指令都可以用来重定向请求,但它们在行为和语法上有一些关键的区别:

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

nginx
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 版本迁移或路径更改时尤其有用。

转换重写规则

  1. documentation https://nginx.org/en/docs/
  2. 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

转换成类似这样的内容:

nginx
# 主服务器块,用于重定向请求
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 定义一个单独的服务器:

nginx
# 为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
# 在较早的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 和“其他所有”:

nginx
# 定义处理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
# 在较早的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]

应该转换为:

nginx
# 转换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
}