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; } } }
http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!!
但行好事 莫问前程
--身高体重180的胖子
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!