• Nginx的rewrite(地址重定向)剖析


    1、rewrite语法:

      指令语法:rewrite regex replacement[flag];

      默认值:none

      应用位置:server、location、if

      rewrite是实现URL重定向的重要指令,他根据regex(正则表达式)来匹配内容跳转到replacement,结尾是flag标记

      简单的小例子:

    1
    rewrite ^/(.*) http://www.baidu.com/ permanent;     # 匹配成功后跳转到百度,执行永久301跳转

      常用正则表达式:

    字符 描述
    将后面接着的字符标记为一个特殊字符或者一个原义字符或一个向后引用
    ^ 匹配输入字符串的起始位置
    $ 匹配输入字符串的结束位置
    * 匹配前面的字符零次或者多次
    + 匹配前面字符串一次或者多次
    ? 匹配前面字符串的零次或者一次
    . 匹配除“ ”之外的所有单个字符
    (pattern) 匹配括号内的pattern

      rewrite 最后一项flag参数:

    标记符号 说明
    last 本条规则匹配完成后继续向下匹配新的location URI规则
    break 本条规则匹配完成后终止,不在匹配任何规则
    redirect 返回302临时重定向
    permanent 返回301永久重定向

    2、应用场景:

    •  调整用户浏览的URL,看起来规范
    • 为了让搜索引擎收录网站内容,让用户体验更好
    • 网站更换新域名后
    • 根据特殊的变量、目录、客户端信息进行跳转

    3、常用301跳转:

      之前我们通过用起别名的方式做到了不同地址访问同一个虚拟主机的资源,现在我们可以用一个更好的方式做到这一点,那就是跳转的方法

      还是用www.brian.com虚拟主机为例子,修改配置文件brian.conf:

    复制代码
    [root@Nginx www_date]# cat brian.conf 
        server {                          # 添加个server区块做跳转
        listen     80;
        server_name  brian.com;
        rewrite ^/(.*) http://www.brian.com/$1 permanent;
        }
        server {
            listen       80;
            server_name  www.brian.com;
            location / {
                root   html/brian;
                index  index.html index.htm;
            }
            access_log logs/brian.log main gzip buffer=128k flush=5s; 
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
     }
    复制代码

       检查语法:

    [root@Nginx conf]# 
    [root@Nginx conf]# ../sbin/nginx -t
    nginx: the configuration file /opt/nginx//conf/nginx.conf syntax is ok
    nginx: configuration file /opt/nginx//conf/nginx.conf test is successful

      平滑重启:

    1
    [root@Nginx conf]# ../sbin/nginx -s reload

      windows测试效果:

    4、域名跳转:

      我们不仅可以做相同虚拟主机的资源域名跳转,也能做不同虚拟主机的域名跳转,我们下面就跳转下当访问brian.com域名的时候跳转到www.baidu.com的页面:

      修改www.brian.com虚拟主机的brian.conf配置文件:

    复制代码
    [root@Nginx www_date]# cat brian.conf 
        server {
            listen       80;
            server_name  brian.com;
            location / {
                root   html/brian;
                index  index.html index.htm;
            }
        if ( $http_host ~* "^(.*)") {
            set $domain $1;
            rewrite ^(.*) http://www.baidu.com break;
        }
            access_log logs/brian.log main gzip buffer=128k flush=5s; 
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
     }
    复制代码

      windows测试:(访问brian.com 跳转到了www.baidu.com)

    加一篇新的解释:

    rewrite模块即ngx_http_rewrite_module模块,主要功能是改写请求URI,是Nginx默认安装的模块。rewrite模块会根据PCRE正则匹配重写URI,然后发起内部跳转再匹配location,或者直接做30x重定向返回客户端。

    rewrite指令的工作原理

    rewrite模块的指令有break, if, return, rewrite, set等。rewrite指令所执行的顺序如下:

    • 首先在server上下文中依照顺序执行rewrite模块指令;
    • 如果server中行了rewrite重写,那么以新URI发起内部跳转,直接匹配location,不会再执行server里的rewrite指令,然后
      • 新URI直接匹配location
      • 如果匹配上某个location,那么其中的rewrite模块指令同样依照顺序执行
      • 如果再次导致URI的rewrite,那么再一次进行内部跳转去匹配location,但跳转的总次数不能超过10次

    rewrite

    基本语法: rewrite regex replacement [flag];
    上下文:server, location, if

    regex是PCRE 风格的,如果regex匹配URI,那么URI就会被替换成replacement,replacement 就是新的URI。如果rewrite同一个上下文中有多个这样的正则,匹配会依照rewrite指令出现的顺序先后依次进行下去,匹配到一个之后并不会终止,而是继续往下匹配,直到返回最后一个匹配上的为止。如果想要中止继续往下匹配,可以使用第三个参数flag。

    如果新URI字符中有关于协议的任何东西,比如http://或者https://等,进一步的处理就终止了,直接返回客户端302。

    如果返回的是30x,那么浏览器根据这个状态码和Location响应头再发起一次请求,然后才能得到想要的响应结果。但是,如果不是返回30x状态码,那么跳转就是内部的,浏览器不做跳转就能得到相应。

    注意:regex直接就是正则表达式,不要再前面添加~符号

    flag 参数可以有以下的一些值:

    last

    如果有last参数,那么停止处理任何rewrite相关的指令,立即用替换后的新URI开始下一轮的location匹配

    break

    停止处理任何rewrite的相关指令,就如同break 指令本身一样。

    last的break的相同点在于,立即停止执行所有当前上下文的rewrite模块指令;不同点在于last参数接着用新的URI马上搜寻新的location,而break不会搜寻新的location,直接用这个新的URI来处理请求,这样能避免重复rewite。因此,在server上下文中使用last,而在location上下文中使用break

    redirect

    replacement 如果不包含协议,仍然是一个新的的URI,那么就用新的URI匹配的location去处理请求,不会返回30x跳转。但是redirect参数可以让这种情况也返回30x(默认302)状态码,就像新的URI包含http://和https://等一样。这样的话,浏览器看到302,就会再发起一次请求,真正返回响应结果的就是这第二个请求。

    permanent

    和redirect参数一样,只不过直接返回301永久重定向

    虽说URI有了新的,但是要拼接成完整的URL还需要当前请求的scheme,以及由server_name_in_redirectport_in_redirect指令决定的HOST和PORT.

    还有一个比较有意思的应用,就是如果replacement中包含请求参数,那么默认情况下旧URI中的请求参数也会拼接在replacement后面作为新的URI,如果不想这么做,可以在replacement的最后面加上?。

    举例说明:

    rewrite ^/users/(.*)$ /show?user=$1? last;

    这样的新URI还是 /show?user=xxx

    但如果不加问号:

    rewrite ^/users/(.*)$ /show?user=$1 last;

    得到的新URI就是/show?user=$1&xxx=xxx。其中xxx=xxx是旧URI所带的请求参数。

    rewrite的例子

    在server中使用的情况:

    server {
        ...
        rewrite ^(/download/.*)/media/(.*)..*$ $1/mp3/$2.mp3 last;
        rewrite ^(/download/.*)/audio/(.*)..*$ $1/mp3/$2.ra  last;
        return  403; #没有匹配上,那就返回403咯
        ...
    }

    注意,在server中使用rewrite ,我们使用的flag是last,但是在location中,我们却只能用break:

    location /download/ {
        rewrite ^(/download/.*)/media/(.*)..*$ $1/mp3/$2.mp3 break;
        rewrite ^(/download/.*)/audio/(.*)..*$ $1/mp3/$2.ra  break;
        return  403;
    }
    

    如果在location的rewrite也使用last,便会再次以新的URI重新发起内部重定向,再次进行location匹配,而新的URI中极有可能和旧的URI一样再次匹配到相同location中,这样死循环发生了。当循环到第10次时,Nginx会终止这样无意义的循环,并返回500错误。这点需要特别的注意。

    break

    基本语法:break;
    上下文:server, location, if

    停止处理任何rewrite的相关指令。如果出现在location里面,那么所有后面的rewrite模块指令都不会再执行,也不发起内部重定向,而是直接用新的URI进一步处理请求。

    server {
      # 访问 /last.html 的时候,页面内容重写到 /index.html 中,并继续后面的location匹配,浏览器地址栏URL地址不变
      rewrite /last.html /index.html last;
    
      # 访问 /break.html 的时候,页面内容重写到 /index.html 中,并停止后续的匹配,浏览器地址栏URL地址不变;
      rewrite /break.html /index.html break;
    
      # 访问 /redirect.html 的时候,页面直接302定向到 /index.html中,浏览器地址URL跳为index.html
      rewrite /redirect.html /index.html redirect;
    
      # 访问 /permanent.html 的时候,页面直接301定向到 /index.html中,浏览器地址URL跳为index.html
      rewrite /permanent.html /index.html permanent;
    
      # 把 /html/*.html => /post/*.html ,301定向
      rewrite ^/html/(.+?).html$ /post/$1.html permanent;
    
      # 把 /search/key => /search.html?keyword=key
      rewrite ^/search/([^/]+?)(/|$) /search.html?keyword=$1 permanent;
      
      # 把当前域名的请求,跳转到新域名上,域名变化但路径不变
      rewrite ^/(.*) http://www.jd.com/$1 permanent;
      }
  • 相关阅读:
    [匈牙利] 洛谷 P2526 小狗散步
    [匈牙利] 洛谷 P1129 矩阵游戏
    [树形dp] Jzoj P5233 概率博弈
    [线段树] Jzoj P4231 寻找神格
    [状压dp][期望] 洛谷 P2473 奖励关
    [倍增][双向链表] Jzoj P3101 开车旅行
    [高精度][数学] Jzoj P3771 小Z的烦恼
    [并查集][排序] Jzoj P2940 生成输入数据
    [dfs][概率] Jzoj P2941 贿赂
    [权值线段树] Jzoj P4417 神奇的字符串
  • 原文地址:https://www.cnblogs.com/wangshaowei/p/12374608.html
Copyright © 2020-2023  润新知