标签:
本文主要针对nginx rewrite指令困惑的地方进行讲解,中间会涉及部分原理部分,我尽量用通俗易懂的语言来形容
The ngx_http_rewrite_module
module directives are processed in the following order:
the directives of this module specified on the server level are executed sequentially;
repeatedly:
NGX_HTTP_SERVER_REWRITE_PHASE,
NGX_HTTP_FIND_CONFIG_PHASE,
NGX_HTTP_REWRITE_PHASE,
NGX_HTTP_POST_REWRITE_PHASE,
/aaa内容aaa
/bbb内容bbb
server { listen 80 ; location /aaa { if ($http_user_agent ~ Mozilla) { rewrite /aaa /bbb; } return 403 ; } location /bbb { return 402 ; } } |
在上述nginx.conf情况下,使用firefox浏览器访问nginx,if匹配成功,执行rewrite重写r->uri(/aaa转换为/bbb),
然后继续执行rewrite模块其他指令,执行到return 403后,该request在nginx中的处理完毕,返回403;
因此浏览器收到应答码为403
server { listen 80 ; location /aaa { if ($http_user_agent ~ Mozilla) { rewrite /aaa /bbb; } # return 403 ; } location /bbb { return 402 ; } } |
在上述nginx.conf情况下,使用firefox浏览器访问nginx,if匹配成功,执行rewrite重写r->uri(/aaa转换为/bbb)
rewrite模块执行完毕。因为所有rewrite模块的指令都执行完毕,进入POST_REWRITE_PHASE所在的checker函数ngx_http_core_post_rewrite_phase
中,由于执行了rewrite指令,在函数ngx_http_script_regex_start_code中
if (code->uri) { r->internal = 1 ; r->valid_unparsed_uri = 0 ; if (code->break_cycle) { //rewrite ....break 指令分支 r->valid_location = 0 ; r->uri_changed = 0 ; } else { r->uri_changed = 1 ; } } |
可以得知r->uri_changed=1,于是在函数ngx_http_core_post_rewrite_phase中执行如下流程
r->uri_changes--; if (r->uri_changes == 0 ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0 , "rewrite or internal redirection cycle " "while processing \"%V\"" , &r->uri); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_OK; } r->phase_handler = ph->next; //ph->next为find_config_index,在ngx_http_init_phase_handlers中可见 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); r->loc_conf = cscf->ctx->loc_conf; |
由于重新进行server和location匹配,因此在上述例子中,浏览器收到的应答状态吗为402
server { listen 80 ; location /aaa { if ($http_user_agent ~ Mozilla) { rewrite /aaa /bbb break ; } return 403 ; } location /bbb { return 402 ; } } |
在上述nginx.conf情况下,使用firefox浏览器访问nginx,if匹配成功,执行rewrite重写r->uri(/aaa转换为/bbb),
由于rewrite break标记符存在,从rewrite指令的配置解析函数ngx_http_rewrite和rewrite模块的handler函数ngx_http_rewrite_handler中
如下部分可以得知,将停止执行rewrite模块的其他一切指令;
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 ; } 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; } ..... ..... ..... if (last) { code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), ®ex); if (code == NULL) { return NGX_CONF_ERROR; } *code = NULL; } } ngx_http_rewrite_handler { ..... ..... while (*(uintptr_t *) e->ip) { code = *(ngx_http_script_code_pt *) e->ip; code(e); } if (e->status < NGX_HTTP_BAD_REQUEST) { //如果rewrite指令后不是break和last标记,而是其他两个重定向标记,则从此处直接结束该request处理流程 return e->status; } if (r->err_status == 0 ) { return e->status; } return r->err_status; ..... ..... } |
进入到POST_REWRITE_PHASE所在的checker函数ngx_http_core_post_rewrite_phase中,由example 2 可知r->uri_changed = 0;
在ngx_http_core_post_rewrite_phase中会执行如下流程,因此会继续执行当前server 和 location 上下文中后续的handler,因此浏览器收到内容为bbb
if (!r->uri_changed) { r->phase_handler++; return NGX_AGAIN; } |
server { listen 80 ; location /aaa { if ($http_user_agent ~ Mozilla) { rewrite /aaa /bbb last; } return 403 ; } location /bbb { return 402 ; } } |
在上述nginx.conf情况下,使用firefox浏览器访问nginx,if匹配成功,执行rewrite重写r->uri(/aaa转换为/bbb),
由于rewrite last标记符存在,停止执行rewrite模块的其他一切指令,参考example 3。
进入到rewrite模块所在的checker函数ngx_http_core_post_rewrite_phase中,由example 2可知r->uri_changed = 1;
于是重新进行server和location匹配,因此在上述例子中,浏览器收到的内容的状态码为402
标签:
原文地址:http://www.cnblogs.com/scottieyuyang/p/5722604.html