7 rewrite 功能

felix.shao2025-02-18

7 rewrite 功能

TIP

 本小节主要介绍以下知识:

  • 后端服务器组的配置指令
  • Rewrite 功能的配置指令
  • Rewrite 功能的多种应用

概述

 主要是用来提供重定向功能。Nginx 服务器的 Rewrite 功能是比较完善的,并且再配置上灵活自由,定制性非常高。

Nginx 后端服务器组的配置的 5 个指令

 服务器组的设置包括几个指令,它们是标准 HTTP 模块 ngx_http_upstream_module 进行解析和处理的。

  1. upstream 指令  该指令是设置后端服务器组的主要指令,其他的指令都在该指令中进行配置。upstream 指令类似于之前提到的 http 块、server 块等,其语法结构为:
    upstream name {...}
     其中,name 是给后端服务器组起的组名。花括号中列出后端服务器组中包含的服务器,其中可以使用下面介绍的其他指令。
     默认情况下,某个服务器组接收到请求以后,按照轮叫调度策略顺序选择组内服务器处理请求。如果一个服务器在处理请求的过程中出现错误,请求会被顺次交给组内的下一个服务器进行处理,以此类推,直到返回正常响应。但如果所有的组内服务器都出错,则返回最后一个服务器的处理结果。

  2. server 指令  该指令用于设置组内的服务器,其语法结构为:
    server adress [parameters];

  • address,服务器的地址,可以是包含端口号的 IP 地址(IP:Port),域名或者以"unix:"为前缀用于进程间通信的 Unix Domain Socket。
  • parameters,为当前服务器配置更多属性。这些属性变量包括以下内容:
1. wright=number,为组内服务器设置权重,权重值高的服务器被有限用于处理请求,默认值为 1;
2. max_fails=number,设置一个请求失败的次数。在一定时间范围内,当对组内某台服务器请求失败的次数超过该变量的值时,认为该服务器无效(down)。默认设置为 1,如果设置为 0,则不使用上面的办法检查服务器是否有效。注意:HTTP 404 状态不被认为是请求失败。
3. fail_timeout=time,有两个作用,一是设置 max_fails 指令尝试请求某台组内服务器的时间,即学习 max_fails 指令尝试请求某台组内服务器的时间,对应上述 2 的时间。另一个作用时在检查服务器是否有效时,如果一台服务器被认为是无效的,该变量设置的时间为认为服务器无效的时间。在这个事件内不再检查该服务器的状态,并一直认为它的无效的,默认设置为 10s。
4. backup,将某台组内服务器标记为备用服务器,只有当正常的服务器处于无效状态或者繁忙状态时,该服务器才被用来处理客户端请求。
5. down,将某台组内服务器标记为永久的无效状态,通常与 ip_hash 指令配合使用。

 示例如下:

upstream backend {
    server backend1.example.com weight=5;
    server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
    server unix:/tmp/backend3;
}
  1. ip_hash 指令  该指令用于实现会话保持功能,将某个客户端的多次请求定向到组内同一台服务器上,保证客户端与服务器之间建立稳定的会话。只有当该服务器处于无效状态时,客户端请求才会被下一个服务器接收和处理。其语法结构为:
    ip_hash;  ip_hash 技术可以避免会话共享问题,但是它有以下的限制:
  • ip_hash 指令不能与 server 指令中的 weight 变量一起使用。
  • nginx 服务器应该是处于最前端的地址,这样才能得到客户端的 IP 地址,否则它得到的 IP 地址将是位于它前面的服务器地址,从而就会产生问题。
  • 客户端 IP 地址必须是 C 类地址(C 类地址的表示范围为:192.0.0.0~223.255.255.255)。

 配置示例如下:

upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
}

4. <b>keepalive 指令</b>
&emsp;该指令用于控制网络连接保持功能。通过该指令,能够保证 Nginx 服务器的工作进程为服务器组打开一部分网络连接,并且将数量控制在一定的范围之内。其语法结构为:  
`keepalive connections;`  
&emsp;其中,connections 为 Nginx 服务器的每一个工作进程允许该服务器组保持的空闲网络连接数的上限数。如果超过该值,工作进程将采用最近最少使用的策略关闭网络连接。 
::: tip
&emsp;该指令不能限制 Nginx 服务器工作进程能够为服务器组开启的总网络连接数。connections 变量在设置时也不要设置得太大,否则会影响服务器组与新网络连接的建立。
:::

5. <b>least_conn 指令</b>
&emsp;该指令用于配置 Nginx 服务器使用负载均衡策略为网络连接分配服务器组内的服务器。该指令在功能上实现了最少连接负载均衡算法,在选择组内的服务器时,考虑各服务器权重的同时,每次选择的都是当前网络连接最少的那台服务器,如果这样的服务器有多台,就采用加权轮叫原则选择权重大的服务器。其语法结构为:  
`least_conn;`  

## rewrite 功能的配置
&emsp;Nginx 服务器的 Rewrite 功能的实现依赖于 PCRE (Perl Compatible Regular Expressions, Perl 兼容的正则表达式)的支持,因此在编译安装 Nginx 服务器之前,需要安装 PCRE 库。  
&emsp;Nginx 服务器使用 ngx_http_rewrite_module 模块解析和处理 Rewrite 功能的相关配置。

### "地址重写"与"地址转发"
&emsp;地址重写:实际上是为了实现地址标准化,即 google.cn 这个地址在服务器中被改变为 www.google..com 的过程就是地址重定向的过程。  
&emsp;转发:是指将一个域名知道另一个已有站点的过程。
&emsp;总结这两个过程的几点区别:  
* 地址转发后客户端浏览器地址栏中的地址显示是不改变的;而地址重写后客户端浏览器地址栏中的地址改变为服务器选择确定的地址。
* 在一次地址转发整个过程中,只产生一次网络请求;而一次地址重写一般会产生两次请求。
* 地址转发一般发生在同一站点项目内,而地址重写没有该限制。
* 地址转发到的页面可以不用全路径名表示,而地址重写到的页面必须使用完整的路径名表示。
* 地址转发过程中,可以将客户端请求的 request 范围内属性传递给新的页面,但地址重写不可以。
* 地址转发的速度较地址重定向快。

### rewrite 规则
&emsp;Rewrite 规则的核心就是 PCRE,核心是正则表达式的配置,这里不对正则表达式概念展开。  

### if 指令
&emsp;该指令用来支持条件判断,并根据条件判断结果选择不同的 Nginx 配置,可以在 server 块和 location 块中配置该指令,其语法结构为:  
`if (condition) {...}`  
&emsp;有以下几种配置方法:  
1. 变量名。如果变量的值为空字符串或者以"0"开头的任意字符串,if 指令认为条件为 false,其他情况认为条件为 true。比如  
``` text 
if($slow){
    ... # nginx 配置
}
  1. 使用"="和"!="比较变量和字符串是否相等,相等时 if 指令认为条件为 true,反之为 false。
if($request_method = POST){
    return 405;
}
  1. 使用正则表达式对变量匹配,匹配成功时 if 指令认为条件为 true,否则为 false。 ::: 整个正则表达式字符串一般不需要加引号,但如果含有右花括号或者分号字符时,必须要给整个正则表达式添加引号 :::

  2. 判断请求的文件是否存在使用"-f"和"!-f"。

  3. 判断请求的目录是否存在使用"-d'和"!-d"。

  4. 判断请求的目录或者文件是否存在使用"-e"和"!-e"。

  5. 判断请求的文件是否可执行使用"-x"和"!-x"。

break 指令

 该指令用于终端当前相同作用域中的其他 Nginx 配置。该指令可以在 server 块和 location 块以及 if 块中使用,其语法结构为:
break;

return 指令

 该指令用于完成对请求的处理,直接向客户端返回响应状态代码。该指令可以在 server 块和 location 块以及 if 块中使用,其语法结构为:

return [text]
return code URL;
return URL;
  • code,为返回给客户端的 HTTP 状态代码。
  • text,为返回给客户端的响应体内容,支持变量的使用。
  • URL,为返回给客户端的URL地址。

rewrite 指令

 该指令通过正则表达式的使用来改变 URI。可以同时存在一个或者多个指令,按照顺序一次对 URL 进行匹配和处理。

TIP

 URI 和 URL 的区别和联系:

  • URI,用于对网络中的各种资源进行标识,由存放资源的主机名、片段标志符和相对 URI 三部分组成。 存放资源的主机名一般由传输协议、主机和资源路径三部分组成; 片段标志符指向资源内容的具体元素; 相对 URI 表示资源在主机上的相对路径。 一般格式为:Scheme:[//][[用户名[:密码]@]主机名[:端口号]][/资源路径]
  • URL,用于在 Internet 中描述资源的字符串,是 URI 的子集,主要包括传输协议、主机和资源具体地址等三部分。 一般格式为:Scheme://主机名[:端口号][/资源路径]

 该指令可以在 server 块或者 location 块中配置,其语法结构为:
rewrite regex replacement [flag];

  • regex,用于匹配 URI 的正则表达式。使用括号"()"标记要截取的内容

TIP

  • rewrite 接收到的 URI 不包含 host 地址。因此 regex 不可能匹配到 URI 的 host 地址,如"http://myweb.com/resource",rewrite 指令匹配到的 URI 是"/resource"。
  • 另外请求 URL 中的请求指令也是不包含在 rewrite 指令接收到的 URI 内容中的。比如:"http://myweb.com/source?arg1=value1",rewrite 指令接收到的 URI 为"/source"。
  • replacement,匹配成功后用于替换 URI 中被截取内容的字符串。默认情况下,如果该字符串是由"http://"或者"https://"开头的,则不会继续向下对 URI 进行其他处理,而直接将重写后的 URI 返回给客户端

TIP

 希望将这些指令传给后端重写后的 URI:
 可以使用 Nginx 全局变量 $request_uri,示例:rewrite myweb.com http://example.com$request_uri?permanet;

  • flag,用来设置 rewrite 对 URI 的处理行为,可以为以下标志中的一个:
1. last,终止继续在本 location 块中处理接收到的 URI,并将此处重写的 URI 作为一个新的 URI,使用各 location 块进行处理。该标志将重写后的 URI 重新在 server 块中执行,为重写后的 URI 提供了转入到其他location 块的机会。如下示例:
location / {
    rewrite ^(/myweb/.*)/media/(.*)\..*$ $1/mp3.$2.mp3 last;
    rewrite ^(/myweb/.*)/audio/(.*)\.*$ $1/mp3.$2.ra last; 
}
如果某 URI 在第 2 行被匹配成功并处理,Nginx 服务器不会继续使用第 3 行的配置匹配和处理新的 URI,而是让所有的 location 块重新匹配和处理新的 URI。

2. break,将此处重写的 URI 作为一个新的 URI,在本块中继续进行处理。该标志将重写后的地址在当前的 location 块中执行,不会将新的 URI 转向到其他 location 块。

3. redirect,将重写后的 URI 返回给客户端,状态代码为 302,指明是临时重定向 URI,主要用在 replacement 变量不是以"http://"或者"https://"开头的情况下。

4. permanent,将重写后的 URI 返回给客户端,状态代码为 301,指明是永久重定向 URI。

TIP

 flag = last时,重写后的 URI 还可能会被该 location 块匹配到,这样就形成了无限循环。Nginx 服务器遇到这样的情况,会尝试 10 次循环之后返回错误状态代码 500。

rewrite_log 指令

 该指令配置是否开启 URL 重写日志的输出功能,其语法结构为:
rewrite_lop on | off
 默认设置为 off。如果配置为开启(on),URL 重写的相关日志将以 notice 级别输出到 error_log 指令配置的日志文件中。

set 指令

 该指令用于设置一个新的变量,其语法结构为:
set variable value

  • variable,为变量的名称,注意要用符号"$"作为变量的第一个字符,且变量不能与 Nginx 服务器预设的全局变量同名。
  • value,为变量的值,可以是字符串、其他变量或变量的组合等。

uninitialized_variable_warn 指令

 该指令用于配置使用未初始化的变量时,是否记录警告日志,其语法结构为:
uninitialized_variable_warn on | off  默认设置为开启(on)状态

rewrite 常用全局变量

变量说明
$args变量中存放了 URL 中的指令,比如http://mobile.weathercn.com/index.do?id=101290101&partner=中的"id=101290101&partner="
$content_length保存了请求报文头部中的 content-lenght 字段
$content_type保存了请求头部中的 content-type 字段
$document_root保存了针对当前资源的请求的系统根目录
$document_uri保存了当前请求中不包含指令的 URI,并且不包括请求指令,比如http://hfnginx.chinacloudapp.cn/index.do?id=101060101&partner=会被定义为"/index.do"
$host存放了请求的服务器名称
$http_user_agent客户端浏览器的详细信息
$http_cookie客户端的 cookie 信息
$limit_rate如果 nginx 服务器使用 limit_rate 配置了显示网络速率,则会显示,如果没有设置, 则显示 0
$remote_addr存放了客户端的地址,注意是客户端的公网 IP,也就是一家人访问一个网站,则会显示为路由器的公网 IP
$remote_port客户端请求 Nginx 服务器时随机打开的端口,这是每个客户端自己的端口
$remote_user已经经过 Auth Basic Module 验证的用户名
$request_body_file做反向代理时发给后端服务器的本地资源的名称
$request_method请求资源的方式,GET/PUT/DELETE 等
$request_filename当前请求的资源文件的路径名称,由 root 或 alias 指令与 URI 请求生成
$request_uri包含请求参数的原始 URI,不包含主机名,如:”/index.do?id=101020100&partner=”
$query_string保存了 URL 请求的指令,与 $args 相同
$scheme请求的协议,如 ftp,https,http 等
$server_protocpl保存了客户端请求资源使用的协议的版本,如 HTTP/1.0,HTTP/1.1,HTTP/2.0 等
$server_addr保存了服务器的 IP 地址
$server_name服务器的主机名
$server_port服务器的端口号
$uri与 $document_uri 相同,是一个不包含指令的 uri 地址

rewrite 的使用

 ngx_http_rewrite_module 是 Nginx 服务器的重要模块之一,它一方面实现了 URL 的重写功能,另一方面为 Nginx 服务器提供反向代理服务提供了支持,同时,我们可以利用 URL 重写功能完成一些其他工作,达到特殊的效果。

域名跳转

 通过 Rewrite 功能可以实现一级域名跳转,也可以实现多级域名跳转。

域名镜像

 镜像网站是指将一个完全相同的网站分别放置到几个服务器上,并分别使用独立的 URL,其中一个服务器上的网站叫主站,其他的为镜像网站。
 使用 Nginx 服务器的 Rewrite 功能可以轻松地实现域名镜像的跳转。可以将整个网站做镜像,或者某一个子目录下的资源做镜像。

独立域名

 当一个网站包含多个板块时,可以为其中的某些板块设置独立域名。其原理和设置某个子目录镜像的原理是相同的。

目录自动添加"/"

 可以解决 /bbs 末尾没有斜杠时,自动添加 /bbs/ 的问题,这样如果由 /bbs/index.htm 就可以访问到。

目录合并

 目录合并主要是将多级目录下的资源文件请求转化为看上去是对目录级数很少的资源的访问。
 比如 http://www.myweb.name/server/12/34/56/78/9.htm 可以通过 nginx 配置为 http://www.myweb.name/server-12-34-56-78-9.htm。

防盗链

 略。

参考文献

  • [Nginx 高性能 Web 服务器详解]
Last Updated 2/18/2025, 5:05:12 PM