本文在这基础上分析nginx服务器收到http请求行、请求头部后,http框架是如何调度各个http模块共同完成这个http请求。例如: http框架调度静态模块,获取服务器目录下的某个html页面返回给客户端; 或者http框架调度access权限访问模块,判断这个客户端是否有权限访问服务器。
一、event事件与http框架的交互
在接收完http请求行、http请求头部后,会调用ngx_http_process_request这个函数开始处理http请求。因为一个http请求由11个处理阶段组成,而每一个处理阶段都允许多个http模块介入,因此在这个函数中,将调度各个阶段的http模块共同完成这个请求。
ngx_http_process_request函数只会被调用一次。如果一次调度并不能处理完11个http阶段,那会将连接对象对应的读事件、写事件回调设置为ngx_http_request_handler。而请求对象的读事件设置为ngx_http_block_reading, 请求对象的写事件回调设置为ngx_http_core_run_phases, 这个回调在ngx_http_handler内设置。这样在事件再次到来时不会调用
ngx_http_process_request函数处理了。那event事件模块的读写事件回调与http请求对象的读写事件回调有什么关系呢?
可以看到,连接对象的读事件回调中,会调用http请求对象的读事件回调。连接对象的写事件回调会调用http请求对象的写事件回调。
图中可看出,在event的读事件发生时,epoll返回后会调用读事件的回调ngx_http_request_handler。在这个读事件回调中,又会调用http框架,也就是http请求对象的读事件回调ngx_http_block_reading,这个http请求对象的读事件回调是不做任何事情的,相当于忽略读事件。因此http框架将会返回到事件模块。那为什么要忽略读事件呢?因为http请求行、请求头部都已经全部接收完成了, 现在要做的是调度各个http模块共同协作,完成对接收到的请求行,请求头部的处理。因此不需要接收来自客户端任何数据了。
对于写事件的处理就复杂多了, 在event的写事件发生时,epoll返回后会调用写事件的回调ngx_http_request_handler,在这个写事件回调中,又会调用http框架,也就是http请求对象的写事件回调ngx_http_core_run_phases。这个http框架的回调会调度介入11个请求阶段的各个http模块的hander方法,共同完成http请求。
二、调度http模块处理请求
在上面代码中,会调度ngx_http_core_run_phases这个函数,使得各个http模块能介入到http请求中来。而这个函数是在ngx_http_handler设置的。
而ngx_http_core_run_phases函数就很简单了,调度介入11个http处理阶段的所有http模块的checker方法。
假设阶段2有三个http模块介入了http请求, 阶段3有一个模块介入了http请求、阶段4也有一个模块介入了请求。当开始处理阶段2时,将调用阶段2中的所有http模块进行处理,此时phase_handler指向阶段2的开始位置。之后每处理完阶段2中的一个模块时,phase_handler指向阶段2的下一个模块,直到阶段2处理完成。
当阶段2中的所有http模块都处理完成时,phase_handler将指向阶段3
因阶段3只有一个http模块,因此当阶段3中的所有http模块都处理完成时,phase_handler将指向阶段4
那这个handlers数组是什么时候创建的呢? 每一个http模块的checker回调又是做什么呢? 接下来将分析这两个问题
三、11个http请求阶段数组创建
在解析nginx.conf配置文件时,解析到http块时,会调用ngx_http_block这个函数开始解析http块。在这个函数中,也会把所有需要介入到11个http请求阶段的http模块,注册到数组中。
例如ngx_http_static_module静态模块,会将自己介入11个http阶段的NGX_HTTP_CONTENT_PHASE阶段回调设置为ngx_http_static_handler
例如: ngx_http_access_module访问权限模块,会将自己介入11个http阶段的NGX_HTTP_ACCESS_PHASE阶段回调设置为ngx_http_access_handler
上面的这些操作,只是把需要介入到11个http阶段的http模块保存到了ngx_http_core_main_conf_t中的phases成员中,并没有保存到phase_engine中。那什么时候将phases的内容保存到phase_engine中呢? 还是在ngx_http_block函数中完成
假设阶段1有一个http模块介入请求,阶段2有三个http模块介入请求、阶段3也有一个http模块介入请求。则ngx_http_init_phase_handlers这个函数调用后,从ngx_http_phase_t phases[11]数组转换到ngx_http_phase_handler_t handlers数组的过程如下图所示:
四、http阶段的checker回调
在11个http处理阶段中,每一个阶段都有一个checker函数,当然有些阶段的checker函数是相同的。对每一个处理阶段,介入这个阶段的所有http模块都共用同一个checker函数。这些checker函数的作用是调度介入这个阶段的所有http模块的handler方法,或者切换到一下个http请求阶段。下面分析下NGX_HTTP_POST_READ_PHASE,NGX_HTTP_PREACCESS_PHASE,NGX_HTTP_LOG_PHASE三个阶段的checker方法。
到此http框架调度各个http模块共同完成http请求已经分析完了,
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
原文链接:http://blog.csdn.net/apelife/article/details/54558112