nginx&http 第三章 ngx 请求处理的 11 个阶段 --ngx_http_process_request& ngx_http_handler

时间:2023-03-09 19:41:51
nginx&http 第三章 ngx 请求处理的 11 个阶段 --ngx_http_process_request& ngx_http_handler
ngx_http_process_request

如果设置了定时器则删除,既然所有的请求已经接收完毕,就不会再发生超时了
重设连接的读写回调函数
重设请求读事件回调函数
调用 ngx_http_handler 处理 HTTP 请求的 11 个阶段
调用 ngx_http_run_posted_requests 处理 posted_requests 队列中的 POST 请
/*
ngx_http_process_request方法负责在接收完HTTP头部后,第一次与各个HTTP模块共同按阶段处理请求,而对于ngx_http_request_handler方法,
如果ngx_http_process_request没能处理完请求,这个请求上的事件再次被触发,那就将由此方法继续处理了。
*/
//ngx_http_process_request_headers头部行解析完毕后调用函数ngx_http_process_request_header
void
ngx_http_process_request(ngx_http_request_t *r)
{
ngx_connection_t *c; c = r->connection; #if (NGX_HTTP_SSL) if (r->http_connection->ssl) {
long rc;
X509 *cert;
ngx_http_ssl_srv_conf_t *sscf; if (c->ssl == NULL) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent plain HTTP request to HTTPS port");
ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS);
return;
} sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); if (sscf->verify) {
rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK
&& (sscf->verify != 3 || !ngx_ssl_verify_error_optional(rc)))
{
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client SSL certificate verify error: (%l:%s)",
rc, X509_verify_cert_error_string(rc)); ngx_ssl_remove_cached_session(sscf->ssl.ctx,
(SSL_get0_session(c->ssl->connection))); ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR);
return;
} if (sscf->verify == 1) {
cert = SSL_get_peer_certificate(c->ssl->connection); if (cert == NULL) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent no required SSL certificate"); ngx_ssl_remove_cached_session(sscf->ssl.ctx,
(SSL_get0_session(c->ssl->connection))); ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT);
return;
} X509_free(cert);
}
}
} #endif
/*
由于现在已经开始准备调用各HTTP模块处理请求了,因此不再存在接收HTTP请求头部超时的问题,那就需要从定时器中把当前连接的读事件移除了。
检查读事件对应的timer_set标志位,力1时表示读事件已经添加到定时器中了,这时需要调用ngx_del_timer从定时器中移除读事件;
*/
if (c->read->timer_set) {//ngx_http_read_request_header中读取不到数据的时候返回NGX_AGIN,会添加定时器和读事件表示继续等待客户端数据到来
ngx_del_timer(c->read, NGX_FUNC_LINE);
} #if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_reading, -1);
r->stat_reading = 0;
(void) ngx_atomic_fetch_add(ngx_stat_writing, 1);
r->stat_writing = 1;
#endif /*
从现在开始不会再需要接收HTTP请求行或者头部,所以需要重新设置当前连接读/写事件的回调方法。在这一步骤中,将同时把读事件、写事件的回调
方法都设置为ngx_http_request_handler方法,请求的后续处理都是通过ngx_http_request_handler方法进行的。
*/
c->read->handler = ngx_http_request_handler; //由读写事件触发ngx_http_request_handler //由epoll读事件在ngx_epoll_process_events触发
c->write->handler = ngx_http_request_handler; //由epoll写事件在ngx_epoll_process_events触发 /*
设置ngx_http_request_t结构体的read_event_handler方法gx_http_block_reading。当再次有读事件到来时,将会调用ngx_http_block_reading方法
处理请求。而这里将它设置为ngx_http_block_reading方法,这个方法可认为不做任何事,它的意义在于,目前已经开始处理HTTP请求,除非某个HTTP模块重新
设置了read_event_handler方法,否则任何读事件都将得不到处理,也可似认为读事件被阻 塞了。
*/
r->read_event_handler = ngx_http_block_reading; //表示暂时不要读取客户端请求 /* ngx_http_process_request和ngx_http_request_handler这两个方法的共通之处在于,它们都会先按阶段调用各个HTTP模块处理请求,再处理post请求 */
ngx_http_handler(r); //这里面会执行ngx_http_core_run_phases,执行11个阶段 /*
HTTP框架无论是调用ngx_http_process_request方法(首次从业务上处理请求)还是ngx_http_request_handler方法(TCP连接上后续的事件触发时)处理
请求,最后都有一个步骤,就是调用ngx_http_run_posted_requests方法处理post请求 11个阶段执行完毕后,调用ngx_http_run_posted_requests方法执行post请求,这里一般都是对subrequest进行处理
*/
ngx_http_run_posted_requests(c); /* */
}

2、处理 HTTP 请求的准备工作 -- ngx_http_handler

在函数中,重新设置了读事件回调,那么请求的写事件回调是在 ngx_http_handler 函数中重设的

//ngx_http_process_request->ngx_http_handler->ngx_http_core_run_phases
//ngx_http_run_posted_requests->ngx_http_handler
void
ngx_http_handler(ngx_http_request_t *r) /* 执行11个阶段的指定阶段 */
{
ngx_http_core_main_conf_t *cmcf; r->connection->log->action = NULL; r->connection->unexpected_eof = 0; /*
检查ngx_http_request_t结构体的internal标志位,如果internal为0,则从头部phase_handler执行;如果internal标志位为1,则表示请求当前需要做内部跳转,
将要把结构体中的phase_handler序号置为server_rewrite_index。注意ngx_http_phase_engine_t结构体中的handlers动态数组中保存了请求需要经历的所有
回调方法,而server_rewrite_index则是handlers数组中NGX_HTTP_SERVER_REWRITE_PHASE处理阶段的第一个ngx_http_phase_handler_t回调方法所处的位置。
究竟handlers数组是怎么使用的呢?事实上,它要配合着ngx_http_request_t结构体的phase_handler序号使用,由phase_handler指定着请求将要执行
的handlers数组中的方法位置。注意,handlers数组中的方法都是由各个HTTP模块实现的,这就是所有HTTP模块能够共同处理请求的原因。
*/
if (!r->internal) { switch (r->headers_in.connection_type) {
case 0:
r->keepalive = (r->http_version > NGX_HTTP_VERSION_10); //指明在1.0以上版本默认是长连接
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);
/*
当internal标志位为0时,表示不需要重定向(如刚开始处理请求时),将phase_handler序号置为0,意味着从ngx_http_phase_engine_t指定数组
的第一个回调方法开始执行(了解ngx_http_phase_engine_t是如何将各HTTP模块的回调方法构造成handlers数组的)。
*/
r->phase_handler = 0; } else {
/*
在这一步骤中,把phase_handler序号设为server_rewrite_index,这意味着无论之前执行到哪一个阶段,马上都要重新从NGX_HTTP_SERVER_REWRITE_PHASE
阶段开始再次执行,这是Nginx的请求可以反复rewrite重定向的基础。
*/
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
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 r->write_event_handler = ngx_http_core_run_phases;
ngx_http_core_run_phases(r);
}

然后这个函数通过请求的 internal 字段判断是否从 0 号回调开始执行最后,就要进入请求的 11 个阶段的处理了 -- ngx_http_core_run_phases

/*
每个ngx_http_phases阶段对应的checker函数,处于同一个阶段的checker函数相同,见ngx_http_init_phase_handlers
NGX_HTTP_SERVER_REWRITE_PHASE ------- ngx_http_core_rewrite_phase
NGX_HTTP_FIND_CONFIG_PHASE ------- ngx_http_core_find_config_phase
NGX_HTTP_REWRITE_PHASE ------- ngx_http_core_rewrite_phase
NGX_HTTP_POST_REWRITE_PHASE ------- ngx_http_core_post_rewrite_phase
NGX_HTTP_ACCESS_PHASE ------- ngx_http_core_access_phase
NGX_HTTP_POST_ACCESS_PHASE ------- ngx_http_core_post_access_phase
NGX_HTTP_TRY_FILES_PHASE ------- NGX_HTTP_TRY_FILES_PHASE
NGX_HTTP_CONTENT_PHASE ------- ngx_http_core_content_phase
其他几个阶段 ------- ngx_http_core_generic_phase HTTP框架为11个阶段实现的checker方法 赋值见 ngx_http_init_phase_handlers
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃ 阶段名称 ┃ checker方法 ┃
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃ NGX_HTTP_POST_READ_PHASE ┃ ngx_http_core_generic_phase ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP SERVER REWRITE PHASE ┃ngx_http_core_rewrite_phase ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP FIND CONFIG PHASE ┃ngx_http_core find config_phase ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP REWRITE PHASE ┃ngx_http_core_rewrite_phase ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP POST REWRITE PHASE ┃ngx_http_core_post_rewrite_phase ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP PREACCESS PHASE ┃ngx_http_core_generic_phase ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP ACCESS PHASE ┃ngx_http_core_access_phase ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP POST ACCESS PHASE ┃ngx_http_core_post_access_phase ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP TRY FILES PHASE ┃ngx_http_core_try_files_phase ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP CONTENT PHASE ┃ngx_http_core_content_phase ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫
┃NGX HTTP LOG PHASE ┃ngx_http_core_generic_phase ┃
┗━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┛
*/
/*
通常来说,在接收完HTTP头部后,是无法在一次Nginx框架的调度中处理完一个请求的。在第一次接收完HTTP头部后,HTTP框架将调度
ngx_http_process_request方法开始处理请求,如果某个checker方法返回了NGX_OK,则将会把控制权交还给Nginx框架。当这个请求
上对应的事件再次触发时,HTTP框架将不会再调度ngx_http_process_request方法处理请求,而是由ngx_http_request_handler方法
开始处理请求。例如recv虽然把头部行内容读取完毕,并能解析完成,但是可能有携带请求内容,内容可能没有读完
*/
//通过执行当前r->phase_handler所指向的阶段的checker函数
//ngx_http_process_request->ngx_http_handler->ngx_http_core_run_phases
void
ngx_http_core_run_phases(ngx_http_request_t *r) //执行该请求对于的阶段的checker(),并获取返回值
{
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; while (ph[r->phase_handler].checker) { //处于同一ngx_http_phases阶段的所有ngx_http_phase_handler_t的checker指向相同的函数,见ngx_http_init_phase_handlers
/*
handler方法其实仅能在checker方法中被调用,而且checker方法由HTTP框架实现,所以可以控制各HTTP模块实现的处理方法在不同的阶段中采用不同的调用行为 ngx_http_request_t结构体中的phase_handler成员将决定执行到哪一阶段,以及下一阶段应当执行哪个HTTP模块实现的内容。可以看到请求的phase_handler成员
会被重置,而HTTP框架实现的checker穷法也会修改phase_handler成员的值 当checker方法的返回值非NGX_OK时,意味着向下执行phase_engine中的各处理方法;反之,当任何一个checker方法返回NGX_OK时,意味着把控制权交还
给Nginx的事件模块,由它根据事件(网络事件、定时器事件、异步I/O事件等)再次调度请求。然而,一个请求多半需要Nginx事件模块多次地调度HTTP模
块处理,也就是在该函数外设置的读/写事件的回调方法ngx_http_request_handler
*/
// 所有的处理阶段回调函数构成了一个链表
// NGX_HTTP_SERVER_REWRITE_PHASE ngx_http_core_rewrite_phase
// NGX_HTTP_FIND_CONFIG_PHASE ngx_http_core_find_config_phase
// NGX_HTTP_REWRITE_PHASE ngx_http_core_rewrite_phase
// NGX_HTTP_POST_REWRITE_PHASE ngx_http_core_post_rewrite_phase
// NGX_HTTP_PREACCESS_PHASE ngx_http_core_generic_phase
// NGX_HTTP_POST_READ_PHASE ngx_http_limit_conn_handler
// NGX_HTTP_ACCESS_PHASE ngx_http_core_access_phase
// NGX_HTTP_POST_ACCESS_PHASE ngx_http_core_post_access_phase
// NGX_HTTP_CONTENT_PHASE ngx_http_core_content_phase
// NGX_HTTP_TRY_FILES_PHASE ngx_http_core_try_files_phase rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]); /* 直接返回NGX OK会使待HTTP框架立刻把控制权交还给epoll事件框架,不再处理当前请求,唯有这个请求上的事件再次被触发才会继续执行。*/
if (rc == NGX_OK) { //执行phase_handler阶段的hecker handler方法后,返回值为NGX_OK,则直接退出,否则继续循环执行checker handler
return;
}
}
}