一、NGINX处理请求11个步骤
nginx将请求划分为11个阶段(phase),便于对请求细分操作处理,与定制化开发:
NGX_HTTP_POST_READ_PHASE // 读取请求阶段
NGX_HTTP_SERVER_REWRITE_PHASE // server级请求rewrite阶段
NGX_HTTP_FIND_CONFIG_PHASE, // 配置查找,location匹配阶段
NGX_HTTP_REWRITE_PHASE, // location级请求重写阶段
NGX_HTTP_POST_REWRITE_PHASE, // server、location级重写后置处理
NGX_HTTP_PREACCESS_PHASE, // 访问权限校验前置处理
NGX_HTTP_ACCESS_PHASE, // 访问权限校验阶段
NGX_HTTP_POST_ACCESS_PHASE, // 访问权限校验后置chuli
NGX_HTTP_PRECONTENT_PHASE, // http请求内容前置处理
NGX_HTTP_CONTENT_PHASE, // http请求内容处理阶段
NGX_HTTP_LOG_PHASE // 日志处理阶段
处理某个请求时,这些phase按顺序执行,处理NGX_HTTP_POST_REWRITE_PHASE阶段处理后,由于server配置与location配置发生变化,需要在配置查找阶段NGX_HTTP_FIND_CONFIG_PHASE重新查找更新配置。其中有部分阶段可挂在自定义的handler回调处理,如下:
NGX_HTTP_POST_READ_PHASE
NGX_HTTP_SERVER_REWRITE_PHASE
NGX_HTTP_REWRITE_PHASE
NGX_HTTP_PREACCESS_PHASE
NGX_HTTP_ACCESS_PHASE
NGX_HTTP_PRECONTENT_PHASE
NGX_HTTP_CONTENT_PHASE
NGX_HTTP_LOG_PHASE
二、可挂载的阶段Handler数组初始化:ngx_http_init_phases
可挂载handler阶段有个明显的特征,就是解析完配置文件之后(ngx_conf_parse)在ngx_http_init_phases创建了对应handler数组
这些数组都是空数组,保存在http配置第一级ctx的main_conf中cmcf = ctx->main_conf[ngx_http_core_module.ctx_index]
;在自定义的handler可通过phase的handlers数组push元素实现挂载。
三、Handler挂载注册:module->postconfiguration
NGINX对于handler的挂载都是在每个module定义的postconfiguration回调方法中完成的。这部分处理也是在ngx_http_block方法中配置文件解析完成之后。postconfiguration回调方法主要两个作用,一个是配置filter,另一个则是为每个可挂载handler的phase挂载module实现的handler。
因此自定义的module,定义好对应的postconfiguration回调方法,再在postconfiguration方法中,取出&cmcf->phase[xxx].handlers数组,在push元素handler即可。通常自定义处理的handler会挂载在NGX_HTTP_CONTENT_PHASE阶段。
四、关联phase与Handler:ngx_http_init_phase_handlers
注册好handler之后,还需要将handler与每个phase的checker做关联:
在NGINX本身的模块的,初始化handler与checker关联关闭后,ph数组的结构如下:
下标14在ph数组中实际上是没有的,图为了完整性,加上了14表示content的下一个阶段是log.。
n和next的变化如下图:
NGX_HTTP_POST_READ_PHASE在NGINX原始配置中,没有handler,不占用ph下标,不过NGX_HTTP_POST_READ_PHASE是可挂载自定义的handler的,如果有自定义的handler,这里下标都要响应后移。
五、phase与Handler执行:ngx_http_core_run_phases
接收请求后,在对请求处理时,会进入ngx_http_core_run_phases方法:
下面来按顺序看下每个节点的phase(checker):
1、NGX_HTTP_POST_READ_PHASE(checker:ngx_http_core_generic_phase)
在NGINX本身的配置中,这个阶段没有handler,另外还有有NGX_HTTP_PREACCESS_PHASE,NGX_HTTP_PRECONTENT_PHASE两个阶段共用这个checker
2、NGX_HTTP_SERVER_REWRITE_PHASE(checker:ngx_http_core_rewrite_phase)
跟ngx_http_core_generic_phase基本差不多,重写server块内,location块外的指令。
handler:ngx_http_rewrite_handler
3、NGX_HTTP_FIND_CONFIG_PHASE(checker:ngx_http_core_find_config_phase)
根据经过server重写阶段的request的uri寻找匹配的location块配置项,由静态字符串标识的location被称作static location,由正则表达式表示的location成为regex location,查找顺序从静态到正则进行匹配,当阶段NGX_HTTP_REWRITE_PHASE发生重写,find config阶段会被执行多次重新匹配location配置。
internal命令使用如下:常用于用户认证后才能访问的资源
location /auth/ {
internal;
root /resource/image/;
}
重定向的request的状态设置为NGX_HTTP_MOVED_PERMANENTLY(301)
如果没有发生重定向,设置request 的ph下标+1,执行下一个Handler,由于findconfig阶段没有Handler,下一个Handler即下一个阶段的第一个Handler:NGX_HTTP_REWRITE_PHASE的第一个Handler。
在发生重定向后重新查找配置,ngx_http_update_location_config(),除了完成keepalive,sendfile,tcp_nopush设置外,还会设置content-handler,完成特定子请求的处理。如ngx_http_proxy_pass()设置clcf->handler = ngx_http_proxy_handler;
4、NGX_HTTP_REWRITE_PHASE(checker:ngx_http_core_rewrite_phase)
与1和2也差不多
handler:ngx_http_rewrite_handler
5、NGX_HTTP_POST_REWRITE_PHASE(checker:ngx_http_core_post_rewrite_phase)
当location重写阶段均发生了重写(location块有重写配置),那么在重写后置处理阶段,则会跳转find config阶段:
重写示例:
访问这以www.a.com访问,但是在NGINX中发生重写,跳转到www.b.com
server {
listen 80;
server_name www.a.com;
rewrite ^/ http://www.b.com permanent;
}
下图第一段红色字体的,server rewrite阶段不包含,serverrewrite已经经过find config阶段了,这里只需要location块发生重写跳转到findconfig。
6、NGX_HTTP_ACCESS_PHASE(checker:ngx_http_core_access_phase)
代码示例:
location /{
satisfy any; //满足一个条件即可
//satisfy all; //满足所有条件
}
handler:ngx_http_access_handler、ngx_http_auth_basic_handler
客户端访问进来的请求会在ngx_http_wait_request_handler-》ngx_http_create_request-》ngx_http_alloc_request()中设置
r->main = r; r->count = 1; 也就是只有主请求的情况下,r->main就是请求r本身,当发生了子请求,如upstream请求,那么会设置子请求sr->main = r.main,那么此时sr->main,就不会等于sr。说明子请求不需要验证access。当发生named内部重新跳转,内部重定向,重写或者upstream等情况,r->main->count会加1,然后在请求后置处理,会逐渐清理重定向的资源,count不断减1,直至减至1,最后清理主请求的资源。内部重定向的一些配置可查看location
7、NGX_HTTP_POST_ACCESS_PHASE (checker:ngx_http_core_access_phase)
主要handler:null
对阶段NGX_HTTP_ACCESS_PHASE处理的access_code做判断,并执行对应的处理
8、NGX_HTTP_CONTENT_PHASE(checker:ngx_http_core_content_phase)
主要涉及的handler有:ngx_http_autoindex_handler、 ngx_http_index_handler、ngx_http_static_handler、ngx_http_proxy_handler
内容产生阶段,可在location配置响应的处理指令,如:perl, flv, proxy_pass, mp4 等。这样request就可以根据对应的content handler处理并返回正确的响应参考
当一个 request 对应的 location 并没有直接有配置的 content handler指令,那么 nginx 依次尝试:
1、 location 里面有配置 random_index on,那么随机选择一个文件,发送给客户端。
2、 location 里面有配置 index 指令,那么发送 index 指令指明的文件,给客户端。
3、 location 里面有配置 autoindex on,那么就发送请求地址对应的服务端路径下的文件列表给客户端。
4、 request 对应的 location 上有设置 gzip_static on,那么就查找是否有对应的.gz文件存在,有的话,就发送这个给客户端(客户端支持 gzip 的情况下)。
5、请求的 URI 如果对应一个静态文件, static module 就发送静态文件的内容到客户端。
例如proxy_pass的处理:
在解析location{}中的proxy_pass配置时,将给对应的clcf设置handler
然后再ngx_http_core_find_config_phase阶段,再查找uri对应的location后,对其更新,将handler赋值给请求r的content_handler,然后再ngx_http_core_content_phase方法最开始就判断是否有r->content_handler,有的话就执行。