nginx中rewrite模块break和last原理详解

原创 2012年04月18日 23:46:20
在使用nginx重写(即rewrite)机制时,大家一般会用到last和break,关于这两个指令的作用,网友问的挺多,网上的讨论也挺多,这里做个总结:
网友的给力解释:
last:
    重新将rewrite后的地址在server标签中执行
break:
    将rewrite后的地址在当前location标签中执行
nginx官方解释:
last:
    stops processing the current set of ngx_http_rewrite_module directives followed by a search for a new location matching     
    the changed URI;
break:
    stops processing the current set of ngx_http_rewrite_module directives;

其实网友的解释更容易懂一些,nginx官方的解释则是从偏重实现的角度来说的,说到这里,许多人可能还是对这两个指令的使用不是太自信,感觉心里没底,说实话我当初也是这么感觉的,那么就让我们打破沙锅问到底,看看代码到底是怎么实现的,毕竟,”代码面前无秘密“。
为了方便我们的讨论我们做出以下的假想配置:
location /download/ { 
    rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;
    rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra  break;
    return  403;
}
在分析之前,看官们需要熟悉nginx各个phase handler的处理,以及nginx变量的基本原理,不熟悉的同学看起来可能会有点难度,那么这里给出了相关的连接,方面不熟悉的同学学习。前两个是关于handler的,后一个是关于变量的:

现在进入正题:
在函数ngx_http_rewrite中:
if (cf->args->nelts == 4) {
        if (ngx_strcmp(value[3].data, "last") == 0) {
            last = 1;

        } else if (ngx_strcmp(value[3].data, "break") == 0) {
            regex->break_cycle = 1;
            last = 1;

        }  
        ...// 其余处理省略
}
重点在于last = 1的处理,在稍后:
if (last) {
    code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), ®ex);
    if (code == NULL) {
        return NGX_CONF_ERROR;
    }

    *code = NULL;
}
lcf->codes是个数组里面保存了当前各个rewrite执行对应的相关操作(即各种handler)和数据,这里的操作是在这个数组中添加一个null,这个null的意义重大,在rewrite实际执行时,如ngx_http_rewrite_handler的调用,就会对事先放置在这个数组里的handler进行处理:
e->ip = rlcf->codes->elts;
...
// 在这个while循环中,上面的那个null,就会终止rewrite一系列操作的执行
// 可以看到,“last”和“break”在这点上作用是相同的,当前codes数组中有剩余的
// rewrite指令,那么由于这里的null的存在,也就跳过不管了。
while (*(uintptr_t *) e->ip) {
    code = *(ngx_http_script_code_pt *) e->ip;
    code(e);
}
比如在开始的配置里面,我们写成:
location /download/ {
    rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3;
    rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra;
    return  403;
}
即不写last和break,那么流程就是依次执行这些rewrite,直到最后以403结束这次请求,这种情况下codes数组中的handler都得以执行了,而由于
last和break的出现,处理可能在中间的某个位置终止,后面的rewrite,就不会执行了。

在rewrite阶段的处理结束之后,则会转到find config阶段,这个阶段本来是在rewrite阶段之前的,这样的过程也刻画了rewrite的基本流程,url经过rewrite阶段被改变了,而一个请求处理的关键步骤之一就是要确定对应的server conf和location conf,而find config的作用恰恰就是如此,重写之后url可以看做是一个新的请求,所以这些关键步骤需要走一遍就是理所当然了。

另一个问题,在ngx_http_rewrite函数中break_cycle的设置,也就是在出现break的时候,这个变量会被置1,而这个变量的设置,最终会导致r->uri_changed被置为0,那么它的直接影响可以在下面的地方看到:
// 这个函数之所以名为“post”,意思就是为rewrite处理做一些善后工作
ngx_http_core_post_rewrite_phase
{   
    // 在通常情况下,即r->uri_changed > 0,r->phase_handler会设置为ph->next,
    // 而这个ph->next,在开始初始化phase的时候,已经设置为ph->next = find_config_index,
    // 所以在非break或者last情况下,之后的phase就是所谓find config阶段了,而这里却是
    // r->phase_handler++,意味着将会执行接下来的处理,不会再去走find config的过程了
    if (!r->uri_changed) {
        r->phase_handler++;
        return NGX_AGAIN;
    }
    ... // 此处省略其他处理部分
}
关于r->uri_changed被置为0的操作,可以参考:
ngx_http_script_regex_start_code和ngx_http_script_break_code

所以这里概括下:
last其实就相当于一个新的url,对nginx进行了一次请求,需要走一遍大多数的处理过程,最重要的是会做一次find config,提供了一个可以转到其他location的配置中处理的机会,而break则是在一个请求处理过程中将原来的url(包括uri和args)改写之后,在继续进行后面的处理,这个重写之后的请求始终都是在同一个location中处理。



nginx rewrite 参数和例子+常用Rewrite伪静态法则

正则表达式匹配,其中: * ~ 为区分大小写匹配* ~* 为不区分大小写匹配* !~和!~*分别为区分大小写不匹配及不区分大小写不匹配 文件及目录匹配,其中: * -f和...
  • zqtsx
  • zqtsx
  • 2014年03月06日 12:08
  • 5015

深入了解linux下的last命令及其数据源

last 数据源: /var/log/wtmp(默认 记录每个用户的登录次数和持续时间等信息)和/var/log/btmp(详细,包括登录失败请求) 数据源格式:二进制(可以通过dump-utmp 命...
  • MINEZHANGHAO
  • MINEZHANGHAO
  • 2013年09月19日 11:01
  • 9652

nginx中的try_files指令解释

try_files 指令的官方介绍比较让人摸不着头脑,经网上一番总结查看,try_files最核心的功能是可以替代rewrite。try_files语法: try_files file … uri 或...
  • ilovemilk
  • ilovemilk
  • 2015年08月20日 20:12
  • 2565

nginx rewrite规则flag参数 break和 last

nginx rewrite规则flag参数 break和 last
  • zckongbai
  • zckongbai
  • 2016年12月12日 10:51
  • 159

nginx rewrite中last和break的区别

在实际配置中,有的地方用last并不能工作,换成break就可以,其中的原理是对于根目录的理解有所区别,按我的测试结果大致是这样的。 #location / { #proxy_pass http:...
  • ZHUBOYAN123
  • ZHUBOYAN123
  • 2013年05月10日 10:19
  • 538

linux Nginx配置篇:rewrite模块参数详解

rewrite和location的功能有点相像,都能实现跳转,主要区别在于rewrite常用于同一域名内更改获取资源的路径,而location是对一类路径做控制访问和反向代理,可以proxy_pass...
  • u010798968
  • u010798968
  • 2017年08月04日 13:13
  • 303

nginx last和break 区别

今天在开发公司官网:http://www.zstime.com/时遇到一个问题,在写rewrite的时候,纠结到底是用last还是break, 后面查看了一下资料,发现它们区别主要是: ...
  • guoshenglong11
  • guoshenglong11
  • 2014年09月16日 22:53
  • 2214

nginx脚本引擎与rewrite设计原理(三)

  • 2012年07月23日 11:05
  • 38KB
  • 下载

nginx的url重写rewrite模块

nginx rewrite模块就是使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现url重写以及重定向。rewrite模块包含的指令有break、if、return、rewri...
  • wangjianno2
  • wangjianno2
  • 2017年07月16日 13:16
  • 426

架构师日记——Nginx的Rewrite模块配置

Rewrite模块用来执行URL重定向。这个机制有利于去掉恶意访问的url,也有利于搜索引擎优化(SEO)Nginx使用的语法源于Perl兼容正则表达式(PCRE)库基本语法如下: ^:必须以^后的实...
  • qq_32198277
  • qq_32198277
  • 2017年07月28日 10:21
  • 160
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:nginx中rewrite模块break和last原理详解
举报原因:
原因补充:

(最多只允许输入30个字)