柴少鹏的官方网站 技术在分享中进步,水平在学习中升华

nginx系列(二)之location与rewrite

http://www.51niux.com/?id=126对nginx做了一些基本的介绍,这里对nginx里面一些经常用到的语法做记录。

一、location配置

location 指令的作用是根据用户请求的URI来执行不同的应用,URI就是根据用户请求到的网址URL进行匹配,匹配成功了进行相关的操作。

location的格式:location [=|~|~*|^~|@] /uri/ { … }

1.1 location分类

一个location可以用prefix string(前缀字符串)定义,也可以通过regular expression(正则表达式来定义)。我们可以通过使用不同的前缀,表达不同的含义,对于不同的前缀可以分为两大类:普通location和正则location,如果你的uri用正则,则你的正则前面必须添加~或者~*。

=:用于普通uri前,要求精确匹配,如果匹配成功,则停止搜索并用当前location处理此请求

~:表示uri包含正则,并且区分大小写
~* :表示uri包含正则,但不区分大小写

^~ : 表示在普通uri前要求Nginx服务器找到普通uri匹配度最高的那个location后,立即处理此请求,并不再进行正则匹配

^~和= : 都可以阻止继续匹配正则location两者的区别:“^~”依然遵守最大前缀原则,然后“=”是需要严格匹配

剩余的正则表达式:
^ :以什么开头的匹配
$ :以什么结尾的匹配
\:转义字符。可以转. * ?等
* :代表任意字符

@:内部访问符,一般用于错误页面等。

+ :匹配前面的子表达式一次或多次

? :匹配前面的子表达式零次或一次

1.2 location的匹配顺序

nginx服务器会首先会检查多个location中是否有普通的uri匹配,如果有多个匹配,会先记住匹配度最高的那个(例如:location /prefix/mid/ {} 和location /prefix/ {} ,对于HTTP 请求/prefix/mid/test.html ,前缀匹配的话两个location 都满足,选哪个?原则是:the most specific match ,于是选的是location /prefix/mid/ {} )。然后再检查正则匹配,这里切记正则匹配是有顺序的,从上到下依次匹配,一旦匹配成功,则结束检查,并就会使用这个location块处理此请求。如果正则匹配全部失败,就会使用刚才记录普通uri匹配度最高的那个location块处理此请求。当普通匹配的最长前缀匹配有符号“^~”的时候,就不会在匹配正则直接使用当前匹配的这个location块处理此请求。

使用符号“=”修饰符可以定义一个精确匹配的URI和位置,如果找到了一个精确的匹配,则搜索终止,例如,如果一个"/”请求频繁发生,定义“location =/"将加快这些请求的处理,一旦精确匹配只有就结束,这样的location显然不能包含嵌套location。“location / {}”是普通的最大前缀匹配,任何的uri肯定是以“/”开头,所以location / {} 可以说是默认匹配,当其他都不匹配了,则匹配默认匹配 。

1.3 location匹配顺序示例测试

location的匹配顺序:

(location =) > (location 完整路径 >) >(location ^~ 路径) >(location ~* 正则) >(location 路径)

       location / {
               return 401;
           }
           location = / {
               return 402;
           }
           location /download/ {
                return 403;
           }
           location ^~ /images/ {
                 return 501;
           }
           location ~* \.(gif|jpg|jpeg)$ {
                 return 502;
           }

图片.png

#location /和location = / 比较,优先匹配的是location = /,从上图中可以看出返回的是402.

图片.png

#首先location =/ 肯定是不匹配了,所以没它什么事了,然后先优先匹配普通location,就剩location /了,好的先记录上,然后正则匹配了一圈发现都匹配不上,然后192.168.1.103/test也是属于/下面,所以返回401了。

location /download 和location /download/的差别:

图片.png

#上面这个例子是比较直观的,如果是192.168.1.103/download,还是认为应该去/下面去找,如果是download/,就根据最大前缀,location /download/比location /前缀要大,所以就返回403了。(因为我们这样定义:location /download的话,那么192.168.1.103/download/和192.168.1.103/download没差别,都是返回403)

正则之前的匹配顺序:

图片.png

#从上图看,首先我们定义了正则/images/和location ~* \.(gif|jpg|jpeg)$,第一个操作是应该匹配前者/images/,第二个操作是匹配结尾是jpg,但是都返回了501,说明正则是从上到下的顺序来匹配。(要是改成location  /images/,就是普通匹配了就优先走正则了,就都返回502了。)

location 普通匹配与正则之间的顺序以及与精确匹配之间的顺序:

图片.png

图片.png

#从上图测试结果看,第一张图location /download/和location ~* \.(gif|jpg|jpeg)$都匹配上了,返回502.就说明虽然优先记录普通结果中的最大前缀记录,但是还是先看看正则有没有,发现正则可以匹配上就优先走正则了。

#从上图测试结果看,第二张图location = / 和location ~* \.(gif|jpg|jpeg)$都匹配上了,location /当然也匹配上了,但是已经有个location =/了就肯定没它啥事了,然后发现结果依旧返回502,所以可以得出结果是location = /相对比较精确,location = /这种设置就是精确到目录稍微深一点就去匹配别的去了,如:http://192.168.1.103/或者http://192.168.1.103这种,就是类似于域名首页啥的。

location ^~遵循最大前缀原则:

   location  ^~ /images/ {
                 return 501;
           }
           location  /images/1/{
                 return 503;
           }

图片.png

#从上图中可以看出location  /images/1/的优先级要高于location  ^~ /images/,因为前者相对路径较深,“^~”依然遵守最大前缀原则,所以前者优先匹配。

location 精确匹配和最长匹配:

 location  /images/1/ {
                 return 501;
           }
 location = /images/1/{
                 return 503;
           }

图片.png

#从上图的结果看。当精确匹配和最长匹配相同时,匹配的是精确匹配。但是当深入到目录中的时候,精确匹配就匹配不上了,然后就走了正则的jpg等资源返回的502了。

location 最大长度匹配与非^~正则匹配之间的顺序:

   location  /images/1/ {
                 return 501;
           }
    location ~ /images/1/ {
                 return 502;
           }

图片.png

#从上图可以看出当最长匹配跟非^~在一起进行匹配的时候,会优先匹配非^~的正则匹配。

1.4 location的一般示例

  location = / {  #第一种访问首页如:www.51niux.com或者192.168.1.103,就直接跳转到百度首页,当然更多的时候是跳转到自己的后端服务器。
               proxy_pass http://wwww.baidu.com/index.php;
           }
  location ^~ /static/ {   #一般我们都会将静态文件放到一个文件里面,当开头是/static/的目录匹配的话就会去/web/test1/static/目录下面查找资源文件
               root /web/test1/static/;
           }
  location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {  #当匹配到后缀是jpg、css等的链接请求,就会去/web/test1/res/下面去查找资源,比如:http://192.168.1.103/dada/5.jpg,就会去/web/test1/res/dada/下面找有没有5.jpg。
               root /web/test1/res/;
           }
  location ~ ^/7[0-9a-z]{    #当匹配到url是/以7开头后面是数字或者小写字母或者是数字和字母的组合,就匹配到了,就可以做一些操作如更改根站点,指向别的机器等。
            root /web/test2/res/;
    }         
  location ~ .*\.(php|php5)?$ {  #当后缀是php或者php5的链接请求时候,会将动态请求交给fastcgi,也就是php的本地9000端口去处理,然后将处理后生成的结果以静态内容的形式发送给客户端,结合上面就算动静分离。
              root           html;   #默认的html是nginx软件安装位置下的html目录
              fastcgi_pass   127.0.0.1:9000; #这就是php的启动ip加端口
              fastcgi_index  index.php;   #首页为index.php
              fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
              include        fastcgi.conf;
         }

#经过上面的配置,站点的根目录下面除了有个首页配置文件以外,剩下的基本全是目录,不同的链接请求去不同的目录里面去找资源。

#当然如果是一个简单的web服务器,就用location做下简单的动静分离就可以了,但是如果是规模比较大的web集群的话,会采用众多的子域名的形式,比如图片的以img.51niux.com的形式提供图片服务。

博文来自:www.51niux.com

二、rewrite精讲

2.1 rewrite规则介绍

rewrite主要的功能是实现URL的重写,nginx的rewrite规则采用PCRE,Perl兼容正则表达式的语法进行规则匹配,如果需要nginx的Rewrite功能,在编译nginx之前,需要编译安装pcre库。

通过rewrite规则,可以实现规则的URL、根据变量来做URL专项及选择配置。例如,一些使用MVC框架的郑旭只有一个入口,可以通过Rewrite来实现。一些动态URL地址需要伪装成静态HTML,便于搜索引擎抓取,也需要Rewrite来处理。一些由于目录结构、域名变化的旧URL,需要跳转到新的URL,也可以通过rewrite来处理。

ngx_http_rewrite_module 模块实现了对 url 的判断、正则匹配、重定向.

2.2 rewrite指令执行顺序

rewrite语法:rewrite regex replacement flag

默认: none
作用域: server, location, if

nginx rewrite执行执行顺序:

  1.   执行server块的rewrite指令

  2.   执行location匹配

  3.   执行选定的location中的rewrite指令

   上述过程可能会嵌套、重复执行,如果其中某步URI被重写,则重新循环执行1-3,直到找到真实存在的文件;循环超过10次,则返回500 Internal Server Error错误。

2.3 flag标志位

last : 相当于Apache的[L]标记,表示完成rewrite,停止处理后续rewrite指令集,last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,一般写在server和if中。

break : 停止处理后续rewrite指令集,break终止重写后的匹配,一般使用在的location中。

redirect : 返回302临时重定向,地址栏会显示跳转后的地址。如果replacement不是以http:// 或https://开始,返回302临时重定向

permanent : 返回301永久重定向,地址栏会显示跳转后的地址。

2.4 if指令与全局变量

if语法为:if(condition){...},对给定的条件condition进行判断。如果为真,大括号内的rewrite指令将被执行,if条件(condtion)可以是下列内容:

  1. 当表达式是一个变量时。如果值为空或任意以0开头的字符串都会被当作false,否则为true,为true就会执行{}里面的rewrite指令。

  2. 直接比较变量和内容时,使用=与!=来匹配是否完全精确相等,~正则表达式的匹配(~*不区分大小写的匹配,!~区分大小写的匹配)。

    3. -f和!-f判断文件是否存在,-d和!-d来判断目录是否存在,-e和!-e来判断文件、链接、目录是否存在,-x和!-x来判断文件是否可执行。

nginx的预定义变量也就是if用的变量:

arg_PARAMETER   #GET请求中变量名PARAMETER参数的值
args  #GET请求中的参数
binary_remote_addr  #二进制码形式的客户端地址
body_bytes_sent  #传送页面的字节数
content_length    #请求头中的Content-length字段
content_type    #请求头中的Content-Type字段
cookie_COOKIE    #cookie COOKIE的值
document_root    #当前请求在root指令中指定的值
document_uri    #与$uri相同
host    #请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称
hostname    #机器名使用 gethostname系统调用的值
http_HEADER    #HTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_
sent_http_HEADER    #HTTP响应头中的内容,HEADER为HTTP响应中的内容转为小写,-变为_
sent_http_content_type    #响应头中的 CONTENT-TYPE 字段
is_args    #如果$args设置,值为"?",否则为""
limit_rate    #这个变量可以限制连接速率
nginx_version    #当前运行的nginx版本号
query_string    #与$args相同
remote_addr    #客户端的IP地址
remote_port    #客户端的端口
remote_user    #已经经过 ngx_auth_basic_module 验证的用户名
request_filename    #当前连接请求的文件路径,由root或alias指令与URI请求生成
request_body    #请求体,主要用于 proxy_pass 或 fastcgi_pass
request_body_file    #客户端请求主体信息的临时文件
request_completion    #如果请求成功,设为"OK";如果请求未完成或者不是一系列请求中最后一部分则设为空
request_method    #这个变量是客户端请求的动作,如GET或POST
request_uri    #包含一些客户端请求参数的原始URI,它无法修改
scheme    #所用的协议,比如http或者是https
server_addr    #服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数
server_name    #服务器名称
server_port    #请求到达服务器的端口号
server_protocol    #请求使用的协议,通常是HTTP/1.0或HTTP/1.1
uri    #请求中的当前URI(不带请求参数,参数位于$args),不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,如 /foo/bar.html
proxy_add_x_forwarded_for   # 获取的是客户端的真实ip地址
proxy_host    #获取upstream的上游代理名称,例如upstream backend
proxy_port    #要代理到的端口
proxy_protocol_addr    #代理头部中客户端的ip地址,或者是一个空的字符串
upstream_addr    #代理到上游的服务器地址信息
upstream_cache_status    #proxy的缓存状态,例如这里第一次访问为MISS,第二次访问时为HIT
upstream_response_length    #上游服务器响应报文的长度
upstream_response_time    #上游服务器响应的时间
upstream_status    #上游服务器响应的状态码

另外,还有个set指令用来创建自定义变量,语法格式为:set variable value;

博文来自:www.51niux.com

2.5 if与rewrite结合示例

示例1.if根据客户端进行跳转

location / {  #这里我们再location里面定义了三个if,注意if不支持if...else这种语法,只支持if一重简单的判断。
               root /web/test1;
               index index.html index.htm;
               if ($http_user_agent ~ MSIE) {   #首先判断客户端的agent信息里面是否包含MSIE,如果条件为真的话,就执行下面的rewrite语句。
               rewrite ^(.*)$ /msie/$1 break;   #^(.*)$指定的  跳转到root指定的/web/test1目录下的/msie目录,$1代表的是^(.*)$,然后配上flag标记break。
               }
               if ($http_user_agent ~ Firefox) {  #这里是匹配浏览器是火狐的
                  rewrite ^(.*)$ /firefox/$1 break;  #指向到了/firefox/目录下面
               }
               if ($http_user_agent ~ Android) {  #这里匹配是是手机客户端系统是android的
                  rewrite ^(.*)$ /android/$1 break;  
               }
 }

# tree -L 2 /web/test1/  #先来查看一下我们的目录结构,根据下图可以看出,根目录下面只有一个index.html文件。

图片.png

测试链接分别为(如果都返回200说明rewrite写的是争取的,因为只有匹配到才会去指向的目录里面去找相关文件):

http://192.168.1.103/haha/666.jpg(IE浏览器)

http://192.168.1.103/10.jpg(安卓手机)

http://192.168.1.103/haha/666.jpg(火狐浏览器)

下面是火狐浏览器的测试结果(测试结果是成功的,注意链接标红的地方,虽然我们后台寻找的目录已经发生了改变,但是前台显示的URL并没有发生变化):

图片.png

查看一下日志信息:

192.168.1.115 - - [14/Jun/2017:15:20:22 +0800] "GET /da/7.jpg HTTP/1.1" "192.168.1.103" 200 109727  17 3 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)" "-" "-" 0.017 423 - -  #IE浏览器的日志信息
192.168.18.196 - - [14/Jun/2017:15:27:01 +0800] "GET /10.jpg HTTP/1.1" "192.168.1.103" 200 54200  18 1 "-" "Mozilla/5.0 (Linux; U; Android 6.0.1; zh-cn; KIW-AL10 Build/HONORKIW-AL10) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 Chrome/37.0.0.0 MQQBrowser/6.0 Mobile Safari/537.36" "-" "-" 0.009 542 - -  #手机浏览器的日志信息
192.168.1.115 - - [14/Jun/2017:15:27:15 +0800] "GET /haha/666.jpg HTTP/1.1" "192.168.1.103" 200 109727  20 1 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0" "-" "-" 0.012 393 - -  #火狐浏览器的日志信息

示例2:if根据请求url做跳转(简单捋顺一下break、last、permanent)

了解一下permanent:(在location下面有一条if语句)

 if ($request_uri ~ sex){
                   rewrite ^(.*)$ /no-s-e-x.html permanent;
               }

图片.png

#从上如可以看出permanent会改变网页URL地址但是会继续向下匹配。

现在我们在同一个location里面有两行判断(了解一下permanent与break):

if ($request_uri ~ sex){   #判断如果请求的url里面带有sex的字样,我们就进行跳转
                   rewrite ^(.*)$ /no-s-e-x.html permanent;  #这里是将所有的内容跳转到根目录下面的一个页面no-s-e-x.html,flag字样是permanent,也就是302状态。
}
if ($http_user_agent ~ Firefox) {  #紧跟着有一个判断是判断浏览器如果是火狐的话,就返回504状态码,然后将所有的内容指定到根目录下面的/firefox/目录下面,然后break。
                  return  504;
                  rewrite ^(.*)$ /firefox/$1 break;
  }

图片.png

#从上面的判断可以看出首先这个if是从上到下执行的,首先先匹配到了输入的url里面含有sex字符串,然后呢就发送了301的跳转,url发送了变化,然后呢竟然没有结束,会继续向下寻找,看一看这个location里面还有没有其他的if可以匹配上。然后我们下面正好有一条是匹配火狐浏览器的,然后就又匹配上了,因为已经发了跳转,所以交给第二个if的url变成了:192.168.1.103/no-s-e-x.html。

#然后就就有个奇怪的地方了,直接到return 504;就直接结束了,并没有到后面的跳转到/firefox目录阶段。是因为return指定是可以返回状态或者url并结束,注意是返回完就结束了。所以一个if里面不要同时存在return和rewrite两条要执行的操作(last和break的结果一样)。

#然后我们把return 504;注释掉,再次测试的话,会发现如果,/firefox目录下面有no-s-e-x.html就返回200状态码,如果不存在就返回404状态码。

结论:

结论1:permanent可以改变前端页面URL,而break和last不会改变前端URL地址。

结论2:permanent就算匹配成功了依旧会在location里面继续向下匹配,所以如果有permanent跳转页面设置应该尽量放到一个location的最下方。

结论3:一个if语句里面,return和rewrite要单独存在,不要同时存在,如果同时存在只会从上到下匹配第一条执行语句。

现在我们在同一个location里面有两行判断(了解一下last与break):

先让break在上面看下结果(在同一个location下面):

   if ($request_uri ~ sex){
                   rewrite ^(.*)$ /login/no-s-e-x.html break;
               }
   if ($http_user_agent ~ Firefox) {
                  rewrite ^(.*)$ /firefox/$1 break;
               }

图片.png

查看日志信息:

192.168.1.115 - - [14/Jun/2017:17:59:04 +0800] "GET /sedasxdsadassex/html.html HTTP/1.1" "192.168.1.103" 200 7  15899 1 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0" "-" "-" 0.001 406 0.001 192.168.1.103:80

#为了方便区分,我firefox里面的no-s-e-x.html文件里面的内容是:firefox no sex,这样就能根据网页显示的内容判断最后到底走的是哪一条if规则。

结论:

flag标记中的break,如果上面的if判断条件判断成功了,就执行本条rewrite指令。不会再向下匹配,到我这条就结束了。是什么就返回什么。如果找不到页面就返回404.简单干脆。

然后我们让last再上面查看下结果(同一个location中):

if ($request_uri ~ sex){
                   rewrite ^(.*)$ /login/no-s-e-x.html last;
               }
if ($http_user_agent ~ Firefox) {
                  rewrite ^(.*)$ /firefox/$1 break;
               }

#这里就不截图了,比如你火狐浏览器输入:http://192.168.1.103/sexsedasxdsadassex/html.html,页面会返回一个500 Internal Server Error错误。为啥返回这个错误呢,是因为第一个匹配上了然后就转换成了/login/no-s-e-x.html文件,但是后面跟的是last而不是break,这就是不是结束了,这就是开始了,然后就开始在同一个server里面找能跟这个转换后的条件匹配上的location,而且是从上到下找三遍,找不到就返回500错误。

下面我们用一个例子验证一下:

location ~ /log {
                 return 406;
           }
location / {
               root /web/test1/;
               index index.html index.htm;
              if ($request_uri ~ sex){
                   rewrite ^(.*)$ /login/no-s-e-x.html last;
               }
               if ($http_user_agent ~ Firefox) {
                  rewrite ^(.*)$ /firefox/$1 break;
               }   
             }             
 location ~ /login {
                return 405;
           }

#在last上下各有一个location,都是可以匹配上的,我们看一下last当它第一次匹配上要去执行的时候,是不是自上而下,还是先向下查找如果找不到再去上面找。

图片.png

#从结果上面可以看出,last匹配一个server里面的location的话是自上而下的。注意是同一个server下面,不能跨server。

#那么我们用last稍微干点事情

  location ~ /login {  #被下面的规则所匹配,把执行任务交给了本location
               root /web/test1/;
               if ($http_user_agent ~ Firefox) {
                  rewrite ^(.*)$ /firefox/no-s-e-x.html break;  #url是没变化的,原封不动的交给我了,然后我想怎么rewrite就是我的事情了,这里我让他去/firefox下面去返回一个提示页面,不要sex
               }
           }
  location / {
               root /web/test1/;
               index index.html index.htm;
               if ($request_uri ~ sex){
                   rewrite ^(.*)$ /login/no-s-e-x.html last;
               }
 }

图片.png

示例3、对url进行切割

 location ~ ^/photos/ {
               rewrite "/photos/([0-9]{2})([0-9]{2})([0-9]{2})" http://192.168.1.103/$1/$2/$3/$1$2$3.jpg permanent;  #这里应该是break,为了测试方便显示效果这里改成了跳转
 }

#注意上面我们可以看到()里面是一个切割块,所以([0-9]{2})([0-9]{2})([0-9]{2}),对应的就是$1,$2,$3。然后就是对{}来说,他们既能用在重定向的正则表达式里,也能用正配置文件里分隔代码块,为了避免冲突,正则表达式里如果带花括号,应该用双引号或者单引号包围。

然后我们进行下测试:

第一个链接:http://192.168.1.103/photos/12345.png   #没有匹配上,所以测试结果是没有跳转

第二个链接:http://192.168.1.103/photos/123456.png   #匹配上了,测试结果是 http://192.168.1.103/12/34/56/123456.jpg,发现png文件变成了jpg文件

第三个链接:http://192.168.1.103/photos/12345678.png   #匹配上了,测试结果是http://192.168.1.103/12/34/56/123456.jpg,发现文件只切割了前六位后两位78不见了

#从上面得到的结果是我们的匹配生效了,只是写的rewrite规则有点low,下面我们稍微改一下,再测试一下:

rewrite "/photos/([0-9]{2})([0-9]{2})([0-9]{1,})\.(png|jpg|gif)$" http://192.168.1.103/$1/$2/$3/$1$2$3.$4 permanent;  #注意这里的\.,就是让这个.不是正则的意思,就是一个单纯的.。

然后再次进行测试:

第一个链接:http://192.168.1.103/photos/12345.png  #测试结果是: http://192.168.1.103/12/34/5/12345.png

第二个链接:http://192.168.1.103/photos/12345678.png   #测试结果是:http://192.168.1.103/12/34/5678/12345678.png

示例4、重定向参数问题

  if ($query_string ~* "id=(\d+)$"){  #如果get请求参数中带有id=数字参数
                      set $id $1;     #set就是设置变量让后给变量赋值,这里就设置了一个id的变量,然后把一堆数字参数赋值给了它(id)。要set一下让下面用$id,如果用$1会有问题。
                      rewrite ^/test\.php /test/$id.html permanent;  #然后如果匹配到了http://域名/test.php?id=一堆数字,就发生跳转变成,http://域名/test/一堆数字.html
  }

测试链接:http://192.168.1.103/test.php?id=123 #测试结果:http://192.168.1.103/test/123.html?id=123  #会发现php的url已经变成了html,但是后面还跟着?id=123。稍微修改下设置:

  if ($query_string ~* "id=(\d+)$"){
                      set $id $1;
                      rewrite ^/test\.php /test/$id.html? permanent;  #就是这里再html后面加了个?后缀。重定向的目标地址结尾处如果加了?号,则不会再转发传递过来原地址的问号?后面的参数那部分。
                      假如又想保留某个特定的参数,那又该如何呢?可以利用Nginx本身就带有的$arg_PARAMETER参数自行补充来实现。例如:
                      把http://192.168.1.103/test.php?para=xxx&p=xx 重写向到 http://192.168.1.103/new.php?p=xx
                      可以写成:rewrite  ^/test.php  /new.php?p=$arg_p?  permanent;
 }

测试链接:http://192.168.1.103/test.php?id=123  #测试结果:http://192.168.1.103/test/123.html  #测试结果后面已经没有?参数了。

示例5、域名间的跳转

先掌握下常用正则:

.   : 匹配除换行符以外的任意字符

? :重复0次或1次

+   : 重复1次或更多次

*    : 重复0次或更多次

\d  : 匹配数字

^   : 匹配字符串的开始

$   :匹配字符串的结束

{n}  : 重复n次

{n,} :重复n次或更多次

[a] : 匹配单个字符a

(a|b|c) :匹配单个字符a或者b或者c

[a-z]:匹配范围a-z,也就是匹配小写字母

\ :转义字符

server {
    listen 80;
    server_name 51niux.cn;
    rewrite (.+) $scheme://www.$host$1 permanent;  #让访问51niux.com直接跳转到www.51niux.com。这里用到了两个变量,将请求都转发到http://www.51niux.com.com/后面。千万不要是$scheme://www.51niux.com/$1,不然结果是http://www.51niux.com.com//内容。

如:url:http://51niux.cn/ceshi/ceshi/ai 会直接跳转成:http://www.51niux.cn/ceshi/ceshi/ai

2.6 简单防盗链的示例

以前是各种防盗链,现在是各种反爬虫。不过设置了防盗链,对于抵制一般的小站来盗链,降低网站的带宽损失还是有好处的。

先了解nginx referer模块:

当一个请求头的Referer字段中包含一些非正确的字段,这个模块可以禁止这个请求访问站点。
这个头可以随意的伪造,因此,使用这个模块并不能100%的阻止这些请求,绝大多数拒绝的请求来自一些典型的浏览器,可以认为这些典型的浏览器并不能提供一个”Referer”头,甚至是那些正确的请求。

再了解下valid_referers 指令:

语法:valid_referers [none|blocked|server_names] …
默认值:no
使用字段:server, location
这个指令在referer头的基础上为 $invalid_referer 变量赋值,其值为0或1。可以使用这个指令来实现防盗链功能,如果valid_referers列表中没有Referer头的值, $invalid_referer将被设置为1。
参数可以使如下形式:
none :意为不存在的Referer头(表示空的,也就是直接访问,比如直接在浏览器打开一个图片)。通常我们用浏览器打开网站,如果你记录$http_referer"字段。会发现其再日志里是-,也就是一个空值。

blocked :意为根据防火墙伪装Referer头,如:“Referer: XXXXXXX”。里面的值被代理或者防火墙删除了,这些值都不以http://或者https://开头.

server_names :为一个或多个服务器的列表,0.5.33版本以后可以在名称中使用“*”通配符。

现在是在server区域里面定义的一个防盗链的location:

  location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {  #这里就是以我们指定的这些jpg啊等等的结尾的文件
                root /web/test1;
                valid_referers none blocked  *.baidu.com$;  #用valid_referers指令定义了一个列表,里面有node、blocked 还有baidu.com的所有域名(多个域名列表之间用空格隔开)
                if ($invalid_referer) {  #如果访问这个location的来源地址不是node blocked或者是来源于百度,$invalid_referer就被设置成1了,也就匹配上这里了。
                 return 403;   #然后就可以对这个非法的来源返回一个http状态,或者可以用rewrite重定向一个我们编写好的网页或者什么。
                 }
          }


作者:忙碌的柴少 分类:Web环境搭建 浏览:3427 评论:0
留言列表
发表评论
来宾的头像