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;
}
}
}

nginx&http 第三章 ngx 请求处理的 11 个阶段 --ngx_http_process_request& ngx_http_handler的更多相关文章

  1. nginx&http 第三章 ngx http ngx_http_process_request_headers

    HTTP 请求行正确处理完成后,针对 HTTP/1.0 及以上版本紧接着要做的就是请求 HEADER 的处理与解析了 /** * 用于处理http的header数据 * 请求头: * Host: lo ...

  2. nginx&http 第三章 ngx HTTP 请求的 11 个处理阶段

    nginx 将一个 HTTP 请求分为 11 个处理阶段,这样做让每一个 HTTP 模块可以仅仅专注于完成一个独立.简单的功能,而一个请求的完整处理过程可以由多个 HTTP 模块共同合作完成将一次 H ...

  3. nginx&http 第三章 ngx http ngx_http_process_request_line读取和处理HTTP头部的行

    在 ngx_http_wait_request_handler 的最后调用了 ngx_http_process_request_line 函数用来处理和解析这次请求的全文 在读事件被触发时,内核套接字 ...

  4. nginx&http 第三章 ngx 1-http ngx_http_wait_request_handler

    对于活跃的 HTTP 连接,在执行连接建立回调函数 ngx_http_init_connection 的过程中会执行 ngx_http_wait_request_handler 回调函数, 负责 HT ...

  5. nginx&http 第三章 ngx http 框架处理流程

    1. nginx 连接结构 ngx_connection_t 这个连接表示是客户端主动发起的.Nginx服务器被动接受的TCP连接,我们可以简单称其为被动连接.同时,在有些请求的处理过程中,Nginx ...

  6. nginx&http 第三章 ngx 事件http 初始化1

    在 http 配置块中,我们配置了 http 连接相关的信息,HTTP 框架也正是从这里启动的 在 nginx 初始化的过程中,执行了 ngx_init_cycle 函数,其中进行了配置文件解析,调用 ...

  7. nginx&http 第三章 ngx 事件event accept epoll /init

    tcp 三次握手成功后,listen fd  可读,在process_event_timer 中调用rev->handler(rev)处理: 其回调函数为: ngx_event_accept / ...

  8. nginx&http 第三章 ngx 事件event epoll 处理

    1. epoll模块命令集 ngx_epoll_commands  epoll模块上下文 ngx_epoll_module_ctx  epoll模块配置 ngx_epoll_module static ...

  9. nginx&http 第四章 ngx http代理 && 转载

    Nginx访问上游服务器的流程大致分以下几个阶段:启动upstream.连接上游服务器.向上游发送请求.接收上游响应(包头/包体).结束请求. upstream相关的两个重要数据结构ngx_http_ ...

随机推荐

  1. 拉格朗日乘子法与KKT条件

    拉格朗日乘子法 \[min \quad f = 2x_1^2+3x_2^2+7x_3^2 \\s.t. \quad 2x_1+x_2 = 1 \\ \quad \quad \quad 2x_2+3x_ ...

  2. 【C语言程序设计】小游戏之俄罗斯方块(二)!适合初学者上手、练手!

    第二篇,主要实现俄罗斯方块中的主体部分,包括容器的数据结构以及容器的相关操作,特别是大方块和容器之间的交互逻辑,包括碰撞检测,消除检测等等. 1. 容器的表示 大方块的实现涉及到位运算,而容器同样如此 ...

  3. 【Targan+LCA】HDU 3686 Traffic Real Time Query

    题目内容 洛谷链接 给出一个\(n\)个节点,\(m\)条边的无向图和两个节点\(s\)和\(t\),问这两个节点的路径中有几个点必须经过. 输入格式 第一行是\(n\)和\(m\). 接下来\(m\ ...

  4. elk-日志方案--使用Filebeat收集日志并输出到Kafka

      1,Filebeat简介 Filebeat是一个使用Go语言实现的轻量型日志采集器.在微服务体系中他与微服务部署在一起收集微服务产生的日志并推送到ELK. 在我们的架构设计中Kafka负责微服务和 ...

  5. swoole热启动

    通过扫描指定的要扫描的目录,把所有文件找出来,分别md5 连接字符串,最后再md5返回 启动定时器,扫描,当前的加密值和以前一样不管,否则就重启服务,把当前赋值给旧值 . httpServer.php ...

  6. 基于gin的golang web开发:路由

    Gin是一个用Golang编写的HTTP网络框架.它的特点是类似于Martini的API,性能更好.在golang web开发领域是一个非常热门的web框架. 启动一个Gin web服务器 使用下面的 ...

  7. Django( 学习第四部 Django的views视)

    目录 视图层 JsonResponse对象 form表单之文件上传 request方法及属性 FBV与CBV JsonResponse对象 前端序列化 JSON.stringify() json.du ...

  8. Stimulsoft报表工具中属性表达式设置属性表达式

    Stimulsoft仪表工具实现所需的数据可视化和自己的信息图表.该产品能够应用必要的过滤器和排序,汇总数据,执行任何复杂度的计算.该产品的优势在于其多功能性-能够为您的业务,财务,销售,行业等任何领 ...

  9. 蒲公英 · JELLY技术周刊 Vol 27: 平平无奇 React 17

    蒲公英 · JELLY技术周刊 Vol.27 这个热闹的十月终于要走到尾声,React 17 历经 4 个 RC 版本之后,也于数天前正式发布了,而同在几天前发布的 CRA 4.0 也已经完成了 Re ...

  10. java关键字之abstract

    Java 允许类,借口或成员方法具有抽象属性. abstract  修饰的类叫做抽象类,该类不能被实例化. abstract  修饰的方法叫抽象方法,抽象方法只有声明部分,没有具体的方法体. 接口总是 ...