nginxhttp模块11个阶段驱动模式详解
1. 处理入口ngx_http_process_request()
关于ngx_http_process_request()
方法,这里首先有两点需要读者理解的:
- nginx是在接收完header数据之后就开始进入http模块的11个阶段进行处理的,这主要是因为,相对于多变的body数据,nginx更关注如何控制header数据的处理;
ngx_http_process_request()
方法只是一个入口方法,最终这个方法将会进入执行http模块11个阶段的调用中,而这个部分是会读取请求的body数据的。由于TCP是流式数据,也就是说一次接收并不一定能够完整的接收所有数据,而且http模块的11个阶段中有部分阶段也可能会要求再次进行当前阶段的调用,这就还是回归到事件框架中了,这个时候会把事件的回调函数设置为ngx_http_request_handler()
方法,根据请求需要,其是可以不断的将控制权交给该方法,以进行再次调用。也就是说这里的ngx_http_process_request()
方法是一个简单的入口方法,而其内部的事件循环驱动的则是ngx_http_request_handler()
方法。
这里我们首先看一下ngx_http_process_request()
方法的源码:
void ngx_http_process_request(ngx_http_request_t *r) { ngx_connection_t *c = r->connection;
if (c->read->timer_set) {
ngx_del_timer(c->read);
}
// 这里的ngx_http_request_handler()方法内部本质上就是根据事件的类型将当前事件委托给
// r->read_event_handler或者r->write_event_handler方法进行处理
c->read->handler = ngx_http_request_handler;
c->write->handler = ngx_http_request_handler;
// 这里将read_event_handler()方法设置为ngx_http_block_reading(),该方法只是将当前的读事件从事件
// 循环中移除了,本质上其是没有做任何事情的,可以理解为读事件的一个空回调方法
r->read_event_handler = ngx_http_block_reading;
// 依次调用http请求的11个阶段处理请求
ngx_http_handler(r);
ngx_http_run_posted_requests(c);
}
可以看出,ngx_http_process_request()
方法主要完成了如下几部分的工作:
- 检查了当前读事件是否超时了,如果超时了,则将其从事件框架中移除;
- 如果读事件没超时,则会将读事件和写事件的回调函数都设置为
ngx_http_request_handler()
方法,这个方法在内部会根据事件的读写类型以判断是重新调用r->read_event_handler()
还是r->write_event_handler()
方法。r->read_event_handler()
方法指针就是下面一行代码所设置的,即ngx_http_block_reading()
,而r->write_event_handler()
方法指针则是在下面的ngx_http_handler()
方法中会进行设置,即ngx_http_core_run_phases()
方法,这个方法是驱动http模块11个阶段的核心方法; - 将
r->read_event_handler
设置为ngx_http_block_reading
,这个方法是一个空方法,其内部只是将当前的读事件移除,这主要是因为当前已经读取完了header数据,而body数据则是有http模块的11个阶段进行处理,因而当前不需要读取连接句柄上的数据; - 调用
ngx_http_handler()
方法以预处理请求,然后进入http模块11个阶段的处理; - 调用
ngx_http_run_posted_requests()
方法,这个方法的主要作用是依次调用当前请求的各个子请求。
2. http模块11个阶段
进入http模块11个阶段的方法是ngx_http_handler()
,这个方法首先会对当前的请求参数进行预处理,这里主要是判断当前请求是不是内部跳转,如果不是,则将请求的阶段从0开始,也即从最开始的一个阶段开始;如果是内部跳转,则直接让当前请求进入server_rewrite阶段。预处理完成后,就会调用ngx_http_core_run_phases()
方法进入http模块11个阶段的链式流程:
/** * 当前方法首先设置当前请求的各个属性,然后调用http的11个阶段的checker()方法处理请求
*/
void ngx_http_handler(ngx_http_request_t *r) {
ngx_http_core_main_conf_t *cmcf;
r->connection->log->action = NULL;
// r->internal为1时表示请求是在内部做跳转
if (!r->internal) {
switch (r->headers_in.connection_type) {
case 0:
r->keepalive = (r->http_version > NGX_HTTP_VERSION_10);
break;
case NGX_HTTP_CONNECTION_CLOSE:
r->keepalive = 0;
break;
case NGX_HTTP_CONNECTION_KEEP_ALIVE:
r->keepalive = 1;
break;
}
r->lingering_close = (r->headers_in.content_length_n > 0 || r->headers_in.chunked);
// 设置当前的处理阶段为初始阶段
r->phase_handler = 0;
} else {
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
// 指定当前的http阶段为server_rewrite_index
r->phase_handler = cmcf->phase_engine.server_rewrite_index;
}
r->valid_location = 1;
#if (NGX_HTTP_GZIP)
r->gzip_tested = 0;
r->gzip_ok = 0;
r->gzip_vary = 0;
#endif
// 设置当前写事件的回调函数为ngx_http_core_run_phases()方法,这样就可以在发生写事件时再次驱动
// http模块的11个阶段
r->write_event_handler = ngx_http_core_run_phases;
ngx_http_core_run_phases(r);
}
这里主要需要强调的一点在于,r->write_event_handler()
方法指针被指向为ngx_http_core_run_phases()
方法,也就是说在发生写事件时,最终就会回调到这个方法。下面我们继续看ngx_http_core_run_phases()
方法:
/** * 调用http请求的11个阶段的checker()方法以处理请求
*/
void ngx_http_core_run_phases(ngx_http_request_t *r) {
ngx_int_t rc;
ngx_http_phase_handler_t *ph;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
ph = cmcf->phase_engine.handlers;
// 这里主要是调用http请求的11个阶段的各个checker()方法依次对请求进行处理
// 这里的phase_handler是在ngx_http_handler()方法中进行设置的,指定了当前将要从http的哪个阶段
// 开始执行,在调用每个checker()方法的时候,该方法内部会对r->phase_handler进行指定,
// 以控制下一步将执行哪一阶段,因而这里没有看到任何控制r->phase_handler的调用
while (ph[r->phase_handler].checker) {
rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
if (rc == NGX_OK) {
return;
}
}
}
ngx_http_core_run_phases()
方法的整体流程是比较简单的,主要就是调用当前请求的各个阶段的回调方法,这里是以一种类似于责任链的方式进行请求的处理的。我们将在后面详细讲解http模块的11个阶段的整体结构,这里我们主要需要理解其控制这个链的方式。上面的链是以数组的方式进行组织的,链的切换是通过r->phase_handler
索引进行的(这也是在前面的ngx_http_handler()
方法中根据是否为内部调用而设置这个参数的原因),链的接口方法就是ph.checker()
,这个方法会返回四种类型的返回值:
- NGX_OK:表示当前阶段已经执行完毕,继续执行下一阶段,需要注意的是,这种情况下,当前阶段的后续方法都不会执行。这个参数能够控制继续执行下一阶段的原因在于,在返回NGX_OK之前,
ph->checker()
方法会将r->phase_handler
指向ph->next
,这里的ph->next
指向的就是下一阶段的第一个节点的索引;
- NGX_DECLINED:表示会继续执行当前阶段的后续方法。这里控制的主要方式是在返回NGX_DECLINED之前,会执行
r->phase_handler++
,这样就可以将索引切换到下一个节点; - NGX_AGAIN和NGX_DONE:表示当前checker方法无法在这一次调用中完成其工作,需要继续多次触发。可以看出来,这里多次触发的方式就是进行下一次的while循环。
3. 事件驱动方式
上面的ph->checker()
方法的返回值如果为NGX_OK,根据while循环的逻辑,就会终止当前方法的调用,此时就会将控制权交给事件驱动。前面我们讲到,当前请求的读写事件的回调函数都设置为了ngx_http_request_handler()
方法,如下是该方法的源码:
/** * 当触发当前连接的读或写事件时,分别调用其write_event_handler()或者read_event_handler()方法
*/
static void ngx_http_request_handler(ngx_event_t *ev) {
ngx_connection_t *c;
ngx_http_request_t *r;
c = ev->data;
r = c->data;
ngx_http_set_log_request(c->log, r);
if (ev->delayed && ev->timedout) {
ev->delayed = 0;
ev->timedout = 0;
}
if (ev->write) {
r->write_event_handler(r);
} else {
r->read_event_handler(r);
}
ngx_http_run_posted_requests(c);
}
这里主要的逻辑就是根据当前的事件类型来控制调用r->write_event_handler()
还是r->read_event_handler()
。而前面我们讲到,r->read_event_handler
指向的是ngx_http_block_reading()
方法,这是一个空的回调方法;r->write_event_handler
指向的是ngx_http_core_run_phases()
方法,也就是我们上面讲解的执行http模块11个阶段的方法,也就是说,通过再次的事件调用,nginx可以控制当前请求继续进行之前未完成的阶段处理。
4. 小结
本文主要讲解了nginx是如何开始进行http模块的11个阶段的驱动的,并且详细介绍了这11个阶段的链式处理方式,最后讲解了nginx是如何通过事件框架不断的驱动http模块11个阶段的运行的。
以上是 nginxhttp模块11个阶段驱动模式详解 的全部内容, 来源链接: utcz.com/z/515184.html