[code.nginx] Rewrite的使用

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

域名跳转

通过Rewrite功能可以实现一级域名跳转,也可以实现多节域名跳转。在server块中配置Rewrite功能即可。
下面是几个例子:


    #  例1
    ...
    server
    {
          listen 80;
          server_name  jump.myweb.name;
          rewrite  ^/  http://jump.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;    #  三级域名跳转
                break;
          }      
          ... #其他配置
    }
    ... #其他配置
    

在上面的例子中展示了通过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。

域名镜像

镜像网站是指将一个完全相同的网站分别放在几个服务器上,并分别放置到几个服务器上,并分别使用独立的URL,其中一个服务器的网站叫做主站,其他的为镜像网站。镜像网站和主站没有太大区别,或者可算是主站的后备。奖项网站可以保存网页信息、历史性数据、以防止丢失。可以通过镜像网站提高网站在不同地区的响应速度。镜像网站可以平衡网站的流量负载,可以解决网络宽带限制、封锁等。
使用Nginx服务器的Rewrite功能可以轻松的实现域名镜像的跳转。其实原理很简单,就是在server块中配置Rewrite功能,将不同的镜像URL重写到指定的URL就可以了。以下是一个供大家参考的配置示例:

      ...
      server
      {
              ...
              listen 80;
              server_name mirror1.myweb.name;
              rewrite ^(.*) http://jump1.myweb.name$1 last;
      }
      server
      {
            ...
            listen 81;
            server_name mirror2.myweb.name;
            rewrite ^(.*) http://jump2.myweb.name$1 last;
      }
      ...

如果我们不想将整个网站做镜像,只想为某一个子目录下的资源做镜像,我们可以在location块中配置Rewrite功能,原理和上面是一样。比如:

        server
        {
                  listen 80;
                  server_name jump.myweb.name;
                  location ^~ /source1
                  {
                            ...
                            rewrite ^/source1(.*) http://jump.myweb.name/websrc2$1 last;
                            break;
                  }
                  location ^~ /source2
                  {
                            ...
                            rewrite ^/source2(.*) http://jump.myweb.name/websrc2$1 last;
                            break;
                  }
                  ...
        }
        ...    #其他配置

独立域名

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


        server
        {
                  ...
                  listen 80;
                  server_name bbs.myweb.com;
                  rewrite ^(.*) http://www.myweb.name/bbs$1 last;
                  break;
        }
        server
        {
                 ...
                 listen 81;
                 server_name  home.myweb.name;
                 rewrite ^(.*) http://www.myweb.name/home$1  last;
                 break;
        }
        ...

目录自动添加“/”

如果网站设定了默认资源文件,那么当客户端使用URL访问时可以不加具体的资源文件名称。比如:在访问www.myweb.name站点时,应该在浏览器地址栏中输入“http://www.myweb.name/index.htm”这样的URL,如果么我们设置了www.myweb.name站点的首页为index.htm,那么直接在地址栏中输入“http://www.myweb.name”即可访问成功,“/index.htm”可以省略不写,现在大家基本上也都习惯了这种访问方式。
当时如果请求的资源文件在二级目录下,这样的习惯可能会造成无法正常访问资源。比如,在访问http://www.myweb.name/bbs/index.htm时,如果将URL省略为“http://www.myweb.name/bbs/”可以进行正常访问,但是如果将URL写为“http://www.myweb.name/bbs”,将末尾的斜杠“/”也省略了,访问就会出问题。
也就是说,Nginx服务器访问二级目录时不加斜杠“/”无法访问。但是我们不可能要求客户端始终按照我们的要求在末尾添加斜杠“/”,那么如果来解决这个问题呢?我们可以使用Rewrite功能为末尾没有斜杠“/”的URL自动添加一个斜杠“/”:

          server
          {
                    ...
                    listen 81;
                    server_name www.myweb.name;
                    location ^~ /bbs
                    {
                              ...
                              if (-d $request_filename)
                              {
                                        rewrite ^/(.*)([^/])$    http://$host/$1$2/  permanent;
                              }   
                    }
          }

在该示例中,我们使用if指令判断请求的“/bbs”是目录以后,匹配接收到的URI串,并将各部分的值截取出来重新组装,并在末尾添加斜杠“/”。注意应该使用permannent标志指名是永久重定向该URI。

目录合并

搜索引擎优化(Search Engine Optimization,SEO)是一种利用搜索引擎的搜索规则来提高目的网站在有关搜索引擎内排名的方式。我们在创建自己的站点时,我们通过一些措施有效提高搜索引擎优化的程度,比如为网页添加包含有有效关键字的标题,在正文中多使用有效关键字,制作网站导航时注意通用规则,尽量避免大量的动态网页,等等。目录合并也是增强SEO的一个方法,它主要将多级目录下的资源文件请求转化为看上去是对目录级数很少的资源的访问。我们来看一个例子,比如在网站中有这样的一个网页,它的路径如下所示:

      [root]/server/12/34/56/78/9.htm

网页9.htm存在于第5级目录下,如果要访问这个资源文件,客户端的URL要写成http://www.myweb.name/server/12/34/56/78/9.htm,这非常不利于搜索引擎的搜索,同时也给客户端的输入带来负担。那么,我们有没有办法让URL的目录级数“看上去”少一写呢?通过Rewrite功能,我们很容易就可以办到。比如我们进行以下的配置:

server
{
        ...
        listen 80;
        server_name www.myweb.com
        location ^~  /server
        {
                ...
                rewrite ~/server-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)\.htm$    /server/$1/$2/$3/$4/$5.html   last;
                break;
        }
}

那么,客户端只要输入“http://www.myweb.name/server-12-34-56-78-9.htm”即可访问到9.htm这个资源文件了。这个URL是不是“看上去”简单多了呢?这其实是充分利用了Rewrite指令支持正则表达式的特性。

防盗链

盗链是一种损害原有网站合法利益,给原网站所在服务器造成额外负担的非法行为。要采取防盗链的措施,首先需要了解盗链的实现原理。
客户端向服务器请求资源时,为了减少网络带宽,提高响应时间,服务器一般不会一次将所有资源完整地传回给客户端。比如在请求一个网页时,首先会传回该网页的文本内容,当客户端浏览器在解析文本的过程中发现有图片存在时,会再次向服务器发起对该图片资源的请求,服务器将存储的图片资源再发送给客户端。在这个过程中,如果该服务器上只包含了网页的文本内容,并没有存放相关的图片资源,而是将图片资源连接到其他站点的服务器上确立,这就形成了盗链行为。在这种情况下,客户端请求的图片资源实际上来自于其他的服务器。很明显,盗链行为是一种对其他服务器不公平的行为。我们在搭建自己的站点时应当有意识地采取防盗链措施。
要实现防盗链,需要了解HTTP协议中的请求头部的Referer头域和采用URL的格式表示访问当前网页或者文件的源地址。通过该头域的值,我们可以检测到访问目标资源的源地址。这样,如果我们检测到Referer头域中的值并不是自己站点内的URL,就采取阻止措施,实现防盗链。但是,需要提醒大家的时,由于Referer头域中的值是可以被更改的,因此该方法不能够完全阻止所有的盗链行为。
知道了盗链行为的原理和防盗链的实现原理,我们就可以利用Nginx服务器的Rewrite功能实现防盗链了。
Nginx的配置中有一个指令valid_referers,用来获取Referer头域中的值,并且根据该值的情况给Nginx全局变量$invalid_referer赋值。如果Referer头域中没有符合valid_referers指令配置的值,$invalid_referer变量将会被赋值为1。valid_referers指令的语法结构为:

        valid_referers none | blocked | server_names | string ...;
  • none,检测Referer头域不存在的情况。
  • blocked,检测Referer头域的值被防火墙或者代理服务器删除或伪装的情况。这种情况下,该头域的值不以“http://”或者“https://”开头。
  • server_names,设置一个或多个URL,检测Referer头域的值是否是这些URL中的某个。从Nginx 0.5.33以后支持使用通配符“*”。

有了valid_referers指令和$invalid_referer变量,就能通过Rewrite功能来实现防盗链。有两种实现方案:一种是根据请求资源的资源类型,一种是根据请求目录。
根据文件类型实现防盗链的一个配置实例如下:

          server
          {
                    ...
                    listen 80;
                    server_name www.myweb.name;
                    location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip)$
                    {
                            ...
                            valid_referers none blocked server_names *.myweb.name;
                            if ($invalid_referer)
                            {
                                      rewrite ^/  http://www.myweb.com/images/forbidden.png;
                            }
                    }  
          }

在配置中,当有网络连接对以gif、jpg、png为后缀的图片资源,以swf、flv为后缀的媒体资源、以rar、zip为后缀的压缩存放资源发起请求时,如果检测到Referer头域中没有符合valid_referers指令配置的值,就将客户单请求的URL重写为http://www.myweb.com/images/forbidden.png,这防止了非法盗链行为。当然我们也可以不重写URL,直接返回HTTP错误状态,如403状态。
根据请求目录实现防盗链的一个配置示例如下:

        server
        {
              ...
              listen 80;
              server_name www.myweb.com
              location  /file/
             {
                  ...
                  root  /server/file/;
                  valid_referers  none  blocked  server_names  *.myweb.com;
                  if ($invalid_referer)
                  {
                          rewrite ^/  http://www.myweb.com/images/forbidden.png;
                  }
             }
        }
        ...

其原理其实和根据文件类型实现防盗链的原理是一样的,只是在location块的url变量上做了改变,对于请求服务器上[root]/server/file/目录下资源采取了防盗链措施。

你可能感兴趣的:([code.nginx] Rewrite的使用)