Nginx的Rewrite功能的使用

386 阅读8分钟
原文链接: click.aliyun.com
  • Rewrite在提供重定向服务时起到主要作用

Nginx后端服务组的配置的指令

  • 是由标准Http模块Ngx_http_upstream_module进行解析和处理的

upstream

  • 设置后端服务器组的主要命令,其他的命令都在该指令中进行配置,upstream指令类似之间的http,server块等

    • 语法:upstream name{...}
    • 默认某个服务器组接收到请求以后,按照轮叫调度(Round-Robin,RR)策略顺序选择组内服务器处理请求.如果一个服务器在处理请求的过程中出现错误,请求会被顺次交给组内的下一个服务器进行处理,直到返回正常响应,但是如果都出错,就返回最后一个服务器的处理结果

server

  • 设置组内的服务器

    • 语法:server address [parameters]
    • parameters为当前服务器配置更多属性

      • weight=number:为组内服务器设置权重,权重高请求优先处理,此时组内服务器的选择策略为加权轮叫策略
      • max_fails=number:设置请求失败的次数.在一定时间范围内,当对组内某台服务器请求失败的次数超过该变量设置的值时,认为该服务器无效.请求失败的各种情况与proxy_next_upstream指令的配置相匹配,默认为1,如果设置为0,则不使用上面的办法检查服务器是否有效,404不被认为是请求失败
      • fail_timeout=time:一是设置max_fails指令尝试请求某台组内服务器的时间,二是在检查服务器是否有效时,如果一台服务器被认为是无效的,该变量设置的时间为认为服务器无效的持续时间,在这个时间内不再检查该服务器的状态,默认10s
      • backup:将某台组内服务器标为备用服务器,只有当正常服务器无效时或繁忙时,该服务器才被用来处理请求
      • down,将某台服务器标为永久的无效状态,通常与ip_hash配合使用
    • server指令配置
      upstream backup{              
        server backendl.example.com weight=5;
        server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
        server unix:/tmp/backend3;
      }
    • 名为backup的服务器组
    • 包含三台服务器:分别是基于域名,基于IP,用于线程通信的Unix Domain Socket.
    • 基于域名的权重设置为5,优先处理请求
    • 基于IP的如果在30s内连续产生3次请求失败,则该服务器在之后的30s被认为是无效状态

ip_hash

  • 用于实现会话保持功能,将某个客户端的多次请求定向到组内同一台服务器上,保证客户端与服务器之间建立稳定的会话,
  • ip_hash机制能够让某一客户机在相当长的一段时间内只访问固定的后端的某台真实的web服务器,这样会话就会得以保持,在网站页面进行login的时候就不会在后面的web服务器之间跳来跳去了,也不会出现登录一次的网站又提醒重新登录的情况.

    • 语法:ip_hash;
    • ip_hash不能与weight一起用,由于ip_hash主要根据客户端IP分配服务器,因此在整个系统中,Nginx服务器应该是处于最前端的服务器,这样才能获取到客户端的IP地址.
    • 案例

      upstream backend{
        ip_hash;
        server myvack1.com;
        server myvack2.com;
      }

keepalive

  • 用于控制网络连接保持功能,通过该指令能够保证Nginx服务器的工作进程为服务器组打开一部分网络连接,并在将数量控制在一定的范围之内

    • 语法:keepalive connections
    • connections:为Nginx服务器的每一个工作进程允许该服务器组保持的空闲网络连接数的上限值,如果超过该值,工作进程将采用最近最少使用的策略关闭网络连接.

least_conn

  • 用于配置Nginx服务器使用负载均衡策略为网络连接分配服务器组内的服务器.在选择上,除了考虑权重问题,每次都会选择的都是当前网络连接最少的那台服务器

    • least_conn;

Rewrite功能的配置

  • Rewrite用于实现URL的重写,比如:更改了网站的结构后,无须要求用户修改原来的标签同样可以访问,并且Nginx服务器的Rewrite功能的实现依赖于PCRE的支持

"地址重写"与"地址转发"

  • 地址重写:比如访问google.cn和www.google.com都会访问谷歌主页,看起来是两个地址都对应了google首页,但实际上google服务器是在不同的地址中选择了www.google.com,反而得到服务器的响应,这个过程就是地址标准化的过程,google.cn在服务器中被改变为www.google.com的过程就是地址重定向的过程
  • 地址转发:是指一个域名指到另一个已有站点的过程
  • 区别:

    • 转发后的浏览器的地址栏的地址是不改变的,而重写后会改变为服务器选择确定的地址
    • 在转发整个过程中,产生一次请求,重写产生两次请求
    • 地址转发一般发生在同一站点项目内,地址重写没有限制
    • 地址转发到的页面可以不用全路径表示,重写页面必须全路径名
    • 转发过程中,可以将请求的request范围内的属性传递给新页面,地址重写不可以
    • 地址转发的速度比重定向快
  • ngx_http_rewrite_module支持URL重写功能,也可以为Nginx服务器提供反向代理服务提供支持.是标准的HTTP服务模块

if

  • 条件判断,在server和location中使用

    • 语法:if(condition){...}
    • 设置方法

      if($slow){...}  #变量名,如果是空字符或者是0开头的字符串,则为false
      if($request_method = POST) #=等于  , != 不等于,并且字符串不需要加字符串
      
      正则表达式匹配
      if($http_user_agent ~ MSIE){...}
      • ~*表示匹配对大小写敏感
      • !~!~*是对上面的取反操作
      • 正则表达式包含"}"和";"时需要给整个正则表达式添加引号
      • -f:如果请求的文件存在,if指令认为条件为true
      • !-f:如果请求的文件不存在但该文件所在的目录存在为true,如果都不存在为false,文件存在也为false
      if(-f $request_filename){判断请求文件是否存在}
      
      if(!-f0 $request_filename){判断请求的文件是否不存在}
      • -d:如果目录存在为true
      • !-d:如果请求的目录不存在但该目录上级目录存在为true
      • e:请求目录或文件存在就为true
      • !-e:请求目录或文件都不存在为true
      • -x:如果请求的文件可执行为true
      • !-x:如果星球文件不可执行为true

break

  • 用于中断当前相同作用域中的其他Nginx配置.在break之前的生效,后面的不生效.如果Nginx服务器遇到该指令,回到上一层作用域继续向下读取配置,可以再server和location,if中使用

    • break
    • 案例

      location / {
        if($slow){
          set $id $1                          #在break之前的生效
          break;
          limit_rate 10k;                     #在break之后的不生效
        }
        ...                                    #其他配置并处于break指令所在作用域的上一层作用域,配置有效
      }

return

  • 用于完成对请求的处理,直接向客户端返回响应状态码,在return之前的生效,后面的不生效,可以再server和location,if中使用

    • 语法:return code URL ; return URL ; return [text]

      • code : http任何状态码,444可以强制关闭服务器与客户端的俩呢及而不返回任何响应信息给客户端
      • text:为返回给客户端的响应体内容,支持变量的使用

rewrite

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

    • 语法:rewrite regex replacement [flag]

      • rewrite接收到URI不包含host地址

        • 请求URL中的请求指令也是不包含在rewrite指令接收到的URI内容中的

          https://www.myweb.com/source?args=1
          #rewrite指令接收到的URI为"/source",不包含"?args=1"
        • 如果想得到请求命令可以使用全局变量$request_uri

          rewrite myweb.com http://example.com$request_uri?permanent;
      • replacement匹配成功后用于替换URI中被截取内容的字符串,默认如果字符串是http://或者https://开头,则不会继续向下对URI进行其他处理.而直接将重写后的URI返回客户端
      • flag:用来设置rewrite对URI的处理行为

        • last:终止继续在本location块中处理接收到的URI,并将此处重写的URI作为一个新的URI,使用各location块进行处理.该标志将重写的URI重新在server中执行,为重写后的URI提供了传入其他location块的机会,尝试10次之后还返回不了,就返回500
        • break:将此处重写的URI作为一个新的URI,在本块中继续进行处理.

          location / {
          rewrite 1... ... break;
          rewrite 2... ... break;
          }
          第二行匹配完,继续匹配第三行
        • redirect:将重写后的URI返回给客户端,状态码为302,指明是临时重定向URI,主要用在replacement变量不是以http://https://开头的情况下
        • permanent:将重写后的URI返回给客户端,状态码为301,指明是永久重定向URI.

rewrite_log

  • 开启重写日志的输出功能

    • rewrite_log on|off;默认off,开启的话日志以notice级别输出到error_log指令的日志文件中

set

  • 设置一个新变量

    • set variable value

      • variable 以 $开头.但是不能与全局变量同名
      • value: 设置的值,可以是各种字符串变量的组合

uninitialized_variable_warn

  • 用于配置使用未初始化的变量时,是否记录警告日志

    • uninitialized_variable_warn on|off默认on

Rewrite全局变量

rw1
rw2


Rewrite的使用

域名跳转

server{
  listen 80;
  server_name localhost;
  rewrite ^(.*) https://www.baidu.com/;           #域名跳转
}

server{
  listen 80;
  server_name jump.myweb.name jumo.myweb.info;
  if($host ~ myweb\.info){
    rewrite ^(.*) https://www.baidu.com$1 permanent;          #多域名跳转
  }          
}

域名镜像

  • 镜像网站是将一个完全相同的网站分别放置到几个服务器上,并分别使用独立的URL
  • 使用Nginx服务器就是在server块中配置rewrite功能,将不同的镜像的URL重写到指定的URL就可以了

    server{
    listen 80;
    server_name mirror1.myweb.name;
    rewrite ^(.*) http://jump1.myweb.name$1 last;
    }
  • 如果不想做整个网站的做镜像,只想为一个子目录下的资源做镜像,可以在location块中配置rewrite

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

独立域名

  • 当一个网站包含多个板块时,可以为其中的某些板块设置独立域名

      server{
    listen 80;
    server_name bbs.web.name;
    rewrite ^(.*) https://www.myweb/bbs$1 last;
    break;
      }

目录自动添加"/"

  • 应用场景:www.web.com输入到网址的时候,如果设置了index,那么就会自动找到index.html.如果在访问二级目录下的文件的时候,比如www.web/com/bbs/index.html时,如果输入www.web.com/bbs/是没有错的.但是输入www.web.com/bbs就会出错,所以这时候就有必要使用这个功能了

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

目录合并

  • 比如要访问index.html,但是他在 /1/2/3/4/5/index.html多级目录下.目录合并就可以简化这个输入,使他看起来少一些

    server{
    listen 80;
    server_name www.myweb.name;
    location ^~ /server{
    rewrite ^/server-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /server/$1/$2/$3/$4/$5.html last;
    break;
    }
    }
    #输入/server-1-2-3-4-5.html,就可以访问文件了

防盗链

  • 盗链的实现原理

    • 客户端向服务器请求资源时,为了减少网络带宽,提高响应时间,服务器一般不会一次将所有资源完整的回传给客户端,比如在请求一个网页时,首先会传回网页的文本内容,当客户端浏览器在解析文本的过程中发现有图片存在时,会再次向服务器发起对图片资源的请求,服务器将存储额图片资源在发送给客户单,在这个过程中,如果该服务器上只包含了网页的文本内容,并没有存储相关的图片资源,而是将图片资源链接到其他站点的服务器上去了,这就形成了盗链的行为.
  • 要实现防盗链,需要了解HTTP协议中的请求头部的Rederer头域和采用URL的格式表示访问当前网页或者文件的源地址,通过该头域的值,就可以检测到访问目标资源的源地址,这样我们如果检测到Referer头域中的值并不是自己站点内的URL,就会采取阻止措施,实现防盗链.但是Rederer可以更改,所以这个方法也不能完全阻止盗链的行为
  • valid_referers

    • 用老获取Rderer头域中的值,并且根据该值的情况给全局变量$invalid_referer赋值,如果头域中没有符合valid_referers指令配置的值,$invalid_referer会被赋值为1
    • valid_referers语法:valid_referers none|blocked |server_names|string...

      • none :检测Rederer头域不存在的情况
      • blocked:检测Referer头域的值被防火墙或者代理服务器删除或伪装的情况,这种情况下,该头域的值不以"http://"或者"https://"开头
      • server_names:设置一个或多个URL,检测Referer头域的值是否是这些URL中的某个,支持*
    • 根据文件类型实现的防盗链

      server{
        listen 80;
        server_name www.myweb.com;
        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;
          }
        }
      }
      #当网络连接对以指定后缀名的图片资源请求时,如果检测到Referer头域中没有符合valid_referers指令配置的值,就将URL重写,也可以直接返回错误码.
    • 根据请求目录实现的防盗链

      server{
        listen 80;
        server_name www.myweb.name;
        location /file/{
          root /server/file/;
          valid_referers none blocked server_names *.myweb.name;
          if($invalid_referer){
            rewrite ^/ http://www.myweb.com/images/forbidden.png
          }
        }
      }
      #对于请求服务器上[root]/server/file/目录下的资源采取了防盗链措施.