浅析Nginx的URL重写rewrite配置详细理解、if指令理解、防盗链理解及实现方式

一、地址重写与地址转发

1、地址重写与地址转发是两个不同的概念。

  地址重写是为了实现地址的标准化,比如我们可以在地址栏中中输入 www.baidu.com,我们也可以输入 www.baidu.cn,最后都会被重写到 www.baidu.com 上。浏览器的地址栏也会显示www.baidu.com。

  地址转发是指在网络数据传输过程中数据分组到达路由器或桥接器后,该设备通过检查分组地址并将数据转发到最近的局域网的过程。

2、因此地址重写和地址转发有以下不同点:

  1. 地址重写会改变浏览器中的地址,使之变成重写成浏览器最新的地址。而地址转发他是不会改变浏览器的地址的。
  2. 地址重写会产生两次请求,而地址转发只会有一次请求。
  3. 地址转发一般发生在同一站点项目内部,而地址重写且不受限制。
  4. 地址转发的速度比地址重定向快。

二、rewrite 指令的基本使用语法

1、基本语法

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

  该指令可以在server块或location块中配置,其基本语法结构如下:

rewrite regex replacement [flag];

2、参数解析

  rewrite是实现URL重定向的重要指令,  
  regex:用来匹配URI的正则表达式;
  replacement:匹配成功后用来替换URI中被截取内容的字符串,默认情况如果该字符串包含“http://”、"https://"开头,则不会继续向下对URI进行其他处理。直接返回重写的URI给客户端
  flag:用来设置rewrite对URI的处理行为,包含如下数据:

last    终止在本location块中处理接收到的URI,并将此处重写的URI作为新的URI使用其他location进行处理。(只是终止当前location的处理)

break   将此处重写的URI作为一个新的URI在当前location中继续执行,并不会将新的URI转向其他location。

redirect    将重写后的URI返回个客户端,状态码是302,表明临时重定向,主要用在replacement字符串不以“http://”,“ https://”或“ $scheme” 开头;

permanent    将重写的URI返回客户端,状态码为301,指明是永久重定向;

rewrite ^/(.*) http://www.baidu.com/$1 permanent;

/* 说明:
rewrite 为固定关键字,表示开始进行rewrite匹配规则。
regex 为 ^/(.*)。 这是一个正则表达式,匹配完整的域名和后面的路径地址。
replacement就是 http://www.baidu.com/$1这块了,其中
$1是取regex部分分组()里面的内容。如果匹配成功后跳转到的URL。
flag 就是 permanent,代表永久重定向的含义,即跳转到 http://www.baidu.com/$1 地址上。
*/

三、if 判断指令

1、语法为 if(condition){…}  对给定的条件condition进行判断,如果为真,大括号内的指令将被执行

2、if 条件(conditon)可以是如下任何内容:

(1)当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false,其他情况为true。

(2)直接比较变量和内容时,使用 = 或 !=

(3)正则表达式匹配,* 不区分大小写的匹配,! 和 !* 反之。

  注意:使用正则表达式字符串一般不需要加引号,但是如果含有右花括号“}”或者分号“;”字符时,必须要给整个正则表达式加引号

(4)其他指令:

  • -f 和 !-f 用来判断请求文件是否存在
  • -d 和 !-d 用来判断请求目录是否存在
  • -e 和 !-e 用来判断是请求的文件或者目录否存在
  • -x 和 !-x 用来判断请求的文件是否可执行

3、正则表达式的基本语法

(1)对变量进行匹配

'~' 表示匹配过程中对大小写敏感。
'~*' 表示匹配过程中对大小写不敏感。
'!~' 如果 '~' 匹配失败时,那么该条件就为true。
'!~*' 如果 '~*' 匹配失败时,那么该条件就为true。

if ($http_user_agent ~ MSIE) {
  // 代码的含义:$http_user_agent值中是否含有 MSIE 字符串,如果包含为true,否则为false
}

(2)判断请求的文件是否存在;判断请求的目录是否存在使用 '-d' 和 '!-d'

if (-f $request_filename) {
  // 判断请求的文件是否存在
}
if (!-f $request_filename) {
  // 判断请求的文件是否不存在
}

四、if 可用的全局变量

  具体如下图,还有$host_host变量,和$host区别如下:$host不带端口,$http_host带端口

五、其他使用指令

1、break 指令

语法:break; 

用于中断当前相同作用域中的Nginx配置,和Java中的break语法类似,可以在server块和location以及if块中使用。

2、return 指令

该指令用于完成对请求的处理,直接向客户端响应状态的代码。和Java中的return语法类似。可以在server块和location以及if块中使用。

语法:

  return code URL;   #code表示状态码,URL表示返回给客户单的URL地址

  或者:return URL;    #当状态码是302或者307的时候,可以使用,返回的URL必须包含“http://”、“https://”或者直接使用“$scheme”变量(RequestScheme代表传输协议,Nginx内置变量)

  或者 return [text];  #为返回给客户端的响应体内容,支持变量的使用

3、rewrite_log指令

该指令用于是否开启URL重写日志的输出,
语法:
  rewrite_log on | off
  默认是off,如果配置为on,URL重写的相关日志将以notice级别输出到error_log指令配置的日志文件中

4、set指令

用来设置新的变量

语法: set variable value;

  variable 这个是变量的名称,这个符号的“$”必须作为变量第一个字符,并且不能和Nginx服务器预设的全局变量同名

  value 为变量的值

  比如 set $id “3”;  #设置id为3

六、理解防盗链及nginx配置

1、什么是防盗链?

  盗链可以理解盗图链接,也就是说把别人的图片偷过来用在自己的服务器上,那么防盗链可以理解为防止其他人把我的图片盗取过去。

2、防盗链的实现原理

  客户端向服务器端请求资源时,为了减少网络带宽,提高响应时间,服务器一般不会一次将所有资源完整地传回客户端。

  比如请求一个网页时,首先会传回该网页的文本内容,当客户端浏览器在解析文本的过程中发现有图片存在时,会再次向服务器发起对该图片资源的请求,服务器将存储的图片资源再发送给客户端。但是如果这个图片是链接到其他站点的服务器上去了呢,比如在我项目中,我引用了的是淘宝中的一张图片的话,那么当我们网站重新加载的时候,就会请求淘宝的服务器,那么这就很有可能造成淘宝服务器负担。因此这个就是盗链行为。因此我们要实现防盗链。

3、实现防盗链:

  使用http协议中请求头部的Referer头域来判断当前访问的网页或文件的源地址。通过该头域的值,我们可以检测访问目标资源的源地址。如果目标源地址不是我们自己站内的URL的话,那么这种情况下,我们采取阻止措施,实现防盗链。

  但是注意的是:Referer头域中的值是可以被更改的。因此该方法也不能完全安全阻止防盗链。

4、使用Nginx服务器的Rewrite功能实现防盗链。

  Nginx中有一个指令 valid_referers,该指令可以用来获取 Referer 头域中的值,并且根据该值的情况给 Nginx 全局变量 invalid_referer 赋值,如果 Referer 头域中没有符合 valid_referers 指令的值的话,invalid_referer变量将会赋值为1。

  valid_referers 指令基本语法如下:

valid_referers  none | blocked | server_names | string

  这里表示请求头部Referer域是否匹配上面值,如果匹配了$invalid_referer 的值为0,没有相匹配就是1;

  因此我们有了 valid_referers 指令和 $invalid_referer 变量的话,我们就可以通过 Rewrite 功能来实现防盗链。

  下面我们介绍两种方案:第一:根据请求资源的类型。第二:根据请求目录。

5、根据请求文件类型实现防盗链配置实列如下:

server {
  listen 8080;
  server_name xxx.abc.com
  location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip)$ {
    valid_referers none blocked www.xxx.com www.yyy.com *.baidu.com  *.tabobao.com;
    if ($invalid_referer) {
      rewrite ^/ http://www.xxx.com/images/forbidden.png;
    }
  }
}

  如上基本配置,当有网络连接对以 gif、jpg、png为后缀的图片资源时候、当有以swf、flv为后缀的媒体资源时、或以 rar、zip为后缀的压缩资源发起请求时,如果检测到Referer头域中没有符合 valid_referers指令的话,那么说明不是本站的资源请求。

  location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip)$ 该配置的含义是 设置防盗链的文件类型。

  valid_referers none blocked www.xxx.com www.yyy.com *.baidu.com *.tabobao.com; 可以理解为白名单,允许文件链出的域名白名单,如果请求的资源文件不是以这些域名开头的话,就说明请求的资源文件不是该域下的请求,因此可以判断它是盗链。因此如果不是该域下的请求,就会使用 Rewrite进行重定向到 http://www.xxx.com/images/forbidden.png 这个图片,比如这张图片是一个x或其他的标识,然后其他的网站就访问不了你这个图片哦。

6、根据请求目录实现防盗链的配置实现如下

server {
  listen 8080;
  server_name xxx.abc.com
  location /file/ {
    root /server/file/;
    valid_referers none blocked www.xxx.com www.yyy.com *.baidu.com  *.tabobao.com;
    if ($invalid_referer) {
      rewrite ^/ http://www.xxx.com/images/forbidden.png;
    }
  }
}

七、相关实例

// 例子一(域名跳转):
server {
  listen 80;
  server_name   abc.com;
  rewrite ^/(.*) http://www.ab c.com/$1 permanent;  # 跳转到www.abc.com网址上
}
// 例子二:
server {
  listen 80;
  server_name   www.myweb.com www.web.info
  if($host ~ web\.info){    #"."需要使用“\”转义,这里是匹配到www.web.info时
    rewrite ^(.*) http://www.myweb.com/&1 permanent;  #永久重定向到http://www.myweb.com网址上&1是匹配的uri
  }
}
// 例子三(防盗链):
location ~* \.(gif|jpg|png|swf|flv)$ {
    valid_referers none blocked www.vison.com www.wsvison.com;  
  #这里表示Referer头域中的值是none或者blocked或者后面这些网址才会返回去正常的gif
|jpg|png|swf|flv文件,否则执行下面if块代码 if ($invalid_referer) { #上面没有匹配成功,$invalid_referer值为1,否则为0 return 404; } //防盗链 } // 其他例子: if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /msie/$1 break; } //如果UA包含"MSIE",rewrite请求到/msid/目录下 if ($http_cookie ~* "id=([^;]+)(?:;|$)") { set $id $1; } //如果cookie匹配正则,设置变量$id等于正则引用部分 if ($request_method = POST) { return 405; } //如果提交方法为POST,则返回状态405(Method not allowed)。return不能返回301,302 if ($slow) { limit_rate 10k; } //限速,$slow可以通过 set 指令设置 if (!-f $request_filename){ break; proxy_pass http://127.0.0.1; } //如果请求的文件名不存在,则反向代理到localhost 。这里的break也是停止rewrite检查 if ($args ~ post=140){ rewrite ^ http://example.com/ permanent; } //如果query string中包含"post=140",永久重定向到example.com

 

posted @ 2017-08-13 22:09  古兰精  阅读(1705)  评论(0编辑  收藏  举报