Nginx服务器的Rewrite功能(二)

2017-12-09 13:28:59

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

    **提示**
    *URI与URL的敬贺和联系*
    URL(Universal Resource Identifier,通用资源标识符),用于对网络中的各种资源进行标识,由存放资源的主机名,片段标志符和相对 URI三部分组成.存放资源的主机名一般由传输协议(Scheme),主机和资源路径三部分组成;片段标志符指向资源内容的具体元素;相对URI表示资源在主机上的相对路径.一般的格式为:Scheme:\[//][用户名[":密码"]@]主机名[:端品号]\[/资源路径].
    该指令可以在server块或者location块中配置,其语法结构为:
    
rewrite regex replacement[flag];

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

rewrite接收到的URL不包含host地址.因此,regex不可能匹配到URI的host地址.我们看下面的例子

rewrite myweb.com http://newweb.com/permanent;

现在我们希望上面的rewrite指令重写http://myweb.com/source 是办不到的,因为rewrite指令接收到的URI是"/source",不包含"myweb.com"

另外,请求URL中的请求指令也是不包含在rewrite指令接收到的URL内容中的.比如:

http://myweb.com/source?agr1=value1&agr2=value2

rewrite指令接收到的URI为"/source",不包含"?agr1=value1&agr2=value2".

  • replacement,匹配成功后用于替换 URI中被截取的字符串.默认情况下,如果该字符串是由"http://" 或者 "https://" 开头的,则不会继续向下对URI进行其他处理,而直接将重写后的URI返回给客户端.

提示
刚才学习regex变量时我们提到 ,rewrite模块接收到的URI不包含请求URL中的请求指令,但是如果我们希望将这些指令传给重写后的URI,该怎么做呢?我们可以使用Nginx全局变量$request_uri,比如 :

rewrite myweb.com http://example.com$request_uri? permantent;

注意
在$request_uri变量后要添加问号"?".replacement变量中支持Nginx全局变量的使用,常用的还有$uri和$args等.

  • flag,用来设置rewrite对URI的处理行为,可以为以下标志中的一个:
  • 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.
  • break,将此处重写的URI作为一个新的URI,在本块中继续进行处理.该标志将重写后的地址在当前的location块中执行,不会将新的URI转向到其它的location块.看下面的例子:
location /myweb/ {
    rewrite ^(/myweb/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;
    rewrite ^(/myweb/.*)/audio/(.*)\..*$ $1/mp3/$2.ra break;
}
  • 如果某URI在第2行被匹配成功并处理,NGINX服务器将新的URI继续在该location块中使用第3行进行匹配和处理.新的URI既给是在同一个location块中
  • redirect,将重写后的URI返回给客户端,状态代码为302,指明是临时重定向URI,主要用在replacement变量不是以"http://" 或者 "https://" 开头的情况.
  • permanent,将重写后的URI返回给客户端,状态代码为301,指明是永久重定向URI
    在使用flag指令时,一定要注意各个标志之间的配合.我们再来回顾刚才学习break标志时的例子,对比last标志里的例子,如果我们将第二个例子中的break标志换成last标志,会发生什么情况呢?

细心的读者可能 已经发现,在第二个例子中,location块的urk指令是"/myweb/",而重写后的URI仍然包含"/myweb/"的,如果使用last标志,重写后的URI还可能会被该location块匹配到,这样就是无限循环.Nginx服务器遇到这样的情况,会尝试10次循环之后返回错误状态代码 500.

rewrite_log指令

该指令配置是否开启URI重写日志的输出功能,其语法结构为:

rewrite_log 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常用全局变量

在下面的表中,笔者列出了一些在Rewrite功能配置过程中可能会使用到的NGINX全局变量,以备以后的查询

变量查询
$args变量中存放了请求URL中的请求指令.比如http://www.myweb.name/server/source?arg1=value1&arg2=value2中的"arg1=value1&arg2=value2"
$content_length变量中存放了请求头中的Content-length字段
$content_type变量中存放了请求头中的Content-type字段
$document_root变量中存放了针对当前请求的根路径
$document_ui变量中存放了请求中的当前URI,并且不包括请求指令,比如http://www.myweb.name/server/source?arg1=value1&arg2=value2中的"/server/source"
$host变量中存放了请求中URL中的主机部分字段,比如http://www.myweb.name/server 中的"www.myweb.name". 如果请求中的主机部分字体不可用或者为空,则存放Nginx配置中该server块中的server_name指令的配置值
$http_user_agent变量中存放客户端的代理信息
$http_cookie变量中存放客户端的cookie信息
$limit_rate变量中存放Nginx服务器对网络连接速率的限制,也就是Nginx配置中limit_rate指令的配置值
$remote_addr变量中存放了客户端的地址
$remote_port变量中存放了客户端与服务器建立连接的端口号
$remote_user变量中存放了客户端的用户名
$request_body_file变量中存放了发给后端服务器的本地文件资源的名称
$request_method变量中存放了客户端的请求方式 ,如"GET","POST"等
$request_filename变量中存放了当前请求的资源文件的路径名
$request_uri变量中存放了当前请求的URI,并且带请求指令
$query_string与变量$args含义相同
$scheme变量中存放了客户端请求使用的协议,比如"http","https"和"ftp"等
$server_protocol变量中存放了客户端请求协议的版本,比如"HTTP/1.0","HTTP/1.1"
$server_addr变量中存放了服务器的地址
$server_name变量中存放了客户端请求到达的服务器的名称
$server_port变量中存放了客户端请求到达的服务器的端口号
$uri与变量$document_uri含义相同
rewrite的使用

ngx_http_rewrite_module是Nginx服务器的重要模块之一,它一方面实现了URL的重写功能 ,另一方面为Nginx服务器提供反向代理服务提供了支持,同时,我们可以利用URL重写功能 完成一些Rewrite功能的其他用法,供大家学习和在实际应用中参考.

域名跳转

通过Rewrite功能可以实现一级域名跳转,也可以实现多级域名跳转.在server块中配置Rewrite功能即可.笔者准备了几个例子供大家参考:

#例1
server
{
    listen 80;
    server_name jump.myweb.name;
    rewrite ^/ http://www.myweb.info/;
    ...
}

#例2
server{
    listen 80;
    server_name jump.myweb.name jump.myweb.info;
    if($host ~ myweb\.info) #注意正则表达示中对点号"."要用'\'进行转义
    {
        rewrite ^(.*) http://jump.myweb.name$1 permanent; #多域名跳转
    }
}

#例3
server{
    listen 80;
    server_name jump1.myweb.name jump2.myweb.name;
    if($http_host ~* ^(.*)\.myweb\.name$)
    {
        rewrite ^(.*) http://jump.myweb.name$1; #三级域名跳转
    }
}

在上面的例子中展示了通过Rewrite功能完成域名跳转的相关配置.
在例1中,客户端访问 http://jump.myweb.name时, URL将被Nginx服务器重写为http://jump.myweb.info; 客户得到的数据其实是由http://jump.myweb.info 响应的.在例2中,客户端访问 http://jump.myweb.info/reqsource时, URL将被Nginx服务器重写为http://jump.myweb.name/reqsource ,客户端得到的数据实际上是由http://jump.myweb.name 响应的.在例3中,客户端访问http://jump1.myweb.name/reqsource 或者http://jump2.myweb.name/reqsource, URL都将被 Nginx服务器重写为http://jump.myweb.name/reqsource, 实现了三级域名的跳转.