Nginx处理HTTP请求
参考资料<深入理解Nginx>(陶辉)
处理HTTP请求
接着上一次的内容,本次将说明HTTP框架是如何召集负责具体功能的各HTTP模块合作处理请求的。
在的最后是通过ngx_http_process_request方法开始处理请求的,该方法流程如下图
2.设置读、写事件的回调方法为ngx_http_request_handler方法,请求的后续处理都是通过ngx_http_request_handler方法进行的。
6.设置ngx_http_request_t结构体的write_event_handler成员为ngx_http_core_run_phases方法。该方法可能会被多次调度来完成HTTP请求的处理。
7.调用ngx_http_core_run_phases回调方法,该方法执行流程如下
ngx_http_request_t结构体中的phase_handler成员(处理流程的核心)将决定执行到哪一阶段,关于该成员跟其相关的数据结构可以查看。
该回调方法的源码如下
void ngx_http_core_run_phases(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_phase_handler_t *ph;
cmcf=ngx_http_get_module_man_conf(r,ngx_http_core_module);
ph=cmcf->phase_engine.handlers;
while(ph[phase_handler].checker){
rc=ph[r->phase_handler].checker(r,&ph[r->phase_hanlder]);
if(rc==NGX_OK){
return;
}
}
}
只有当相应的checker方法返回NGX_OK时才将控制权交还给Nginx的事件模块,否则将继续执行(checker方法中会修改phase_handler成员以向下执行)。
当这个请求上对应的事件再次触发时,HTTP框架将回调ngx_http_request_handler方法开始处理请求(上面已经设置了该方法为其读、写事件的回调方法)。
下图是ngx_http_request_handler方法的流程
2.如果当前事件可写,将调用ngx_http_reqeust_t结构体中的write_event_handler方法。该方法在上面已经设置为ngx_http_core_run_phases,可见该方法会被多次调用。
Checker方法
checker方法是HTTP框架定义的,每一个HTTP处理阶段对应着相应着一个checker方法(有的阶段的checker方法一样),handler方法只有在checker方法中调用。
checker方法的主要任务在于,根据phase_handler执行某个HTTP模块实现的回调方法,并根据方法的返回值决定:
1.当前阶段是否已经结束
2.下次要执行的回调方法是哪一个
3.是立刻执行下一个回调方法还是先把控制权交还给epoll
下面介绍HTTP框架中其中两个checker方法的介绍
ngx_http_core_generic_phase
在前面的下面有该方法的介绍,下面只给出该方法的流程图
可见,checker方法主要是根据handler方法的返回值来改变phase_handler的值以用来控制handler方法的执行顺序的。
ngx_http_core_content_phase
ngx_http_core_content_phase是NGX_HTTP_CONTENT_PHASE阶段的checker方法。是我们开发HTTP模块时最常用的一个阶段。
其余10个阶段中各HTTP模块的handler方法都是放在全局ngx_http_core_main_conf_t结构体中,而该阶段的handler方法则可以放在ngx_http_core_conf_t结构体中,这就是按需挂载的基础
typedef struct ngx_http_core_loc_conf_s ngx_http_core_loc_conf_t
struct ngx_http_core_loc_conf_s {
...
ngx_http_handler_pt handler;
...
}
在我们最初的开发的HTTP模块中:
当检测到mytest配置项后,调用ngx_http_mytest方法将上面ngx_http_core_loc_conf_t的handler成员设置为自己的handler函数,实现了按需挂载。
事实上,在NGX_HTTP_FIND_CONFIG_PHASE阶段就会把ngx_http_request_t结构体的content_handler成员设置为匹配请求URI的location下的ngx_http_core_loc_conf_t结构体的handler成员。
下面是该checker方法的流程图,可以看出是如何实现按需挂载的
处理HTTP包体
在接收完HTTP头部后,就开始调用各HTTP模块处理请求了,然后由HTTP模块决定如何处理包体(handler函数)。
1.接收包体
ngx_int_t ngx_http_read_client_request_body(ngx_http_request *r,ngx_http_client_body_handler_pt post_handler);
typedef void (*ngx_http_client_body_handler_pt) (ngx_http_request_t *r);
接收到的包体保存在ngx_http_reqeust_body_t中,一般调用该函数的handler函数会接着返回NGX_DONE。
在完成接收动作之后,会调用post_handler函数继续处理请求。
2.放弃接收包体(Nginx必须接收包体,但不做处理)
ngx_int ngx_http_discard_reqeust_body(ngx_http_request_t *r);
调用该函数的handler函数继续处理请求,Nginx会异步地接收跟丢弃包体。
发送HTTP响应
显然,发送HTTP响应也是在handler函数中调用的。
1.发送响应头
ngx_int_t ngx_http_send_header(ngx_http_request_t *r);
该方法会异步地根据ngx_http_reqeust_t中的header_out成员将HTTP头部发送给客户端(经过各个过滤模块)。
2.发送响应体
ngx_int_t ngx_http_output_filter(ngx_http_request_t *r,ngx_chain_t *in);
该方法会异步地根据参数in将HTTP响应体发送给客户端(经过各个过滤模块)。