从源码角度理解nginx中last与break的区别

发布时间:2019-12-09编辑:脚本学堂
在nginx 配置文件中经常会用到last与break指令。两者之间的区别在哪里呢?以nginx-1.0.14的源码为例:/src/http/modules/ngx_http_rewrite_module.c (366-389行)

nginx 配置文件中经常会用到last与break指令。两者之间的区别在哪里呢?

以nginx-1.0.14的源码为例:
/src/http/modules/ngx_http_rewrite_module.c (366-389行)
 

复制代码 代码如下:

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;

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

} else if (ngx_strcmp(value[3].data, "permanent") == 0) {
regex->status = NGX_HTTP_MOVED_PERMANENTLY;
regex->redirect = 1;
last = 1;

} else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter "%V"", &value[3]);
return NGX_CONF_ERROR;
}
}

break 与last的区别在于多了一行,regex->break_cycle = 1; 那么我们来看看这行语句具体有何含义。
break_cycle赋值后会被ngx_http_script_regex_code_t *code 调用。

具体在/src/http/ngx_http_script.c (1007行),代码段如下:
 

复制代码 代码如下:

if (code->break_cycle) {
r->valid_location = 0;
r->uri_changed = 0;

} else {
r->uri_changed = 1;
}

r->valid_location = 0; 表示break指令不会继续作用于之后的location域。
r->uri_changed = 0;表示break指令停止继续匹配。而last指令会继续匹配下去。
继续看如下代码
/src/http/ngx_http_core_module.c(1038行)
 

复制代码 代码如下:

ngx_http_core_post_rewrite_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph)
{
ngx_http_core_srv_conf_t *cscf;

ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"post rewrite phase: %ui", r->phase_handler);

if (!r->uri_changed) {
r->phase_handler++;
return NGX_AGAIN;
}

r->uri_changed = 0; 内核会跳出处理下一个请求。
last指令 r->uri_changed = 1; 会继续不停的匹配。

总结:使用break指令后,不会继续作用于随后的location域,不会循环继续匹配。last指令恰恰相反。
从效率上来说尽量使用break指令。