HTTP框架动态执行中的大概流程:先与客户端建立TCP连接,接收HTTP请求行、头部并解析出他们的意义,再根据nginx.conf配置文件找到一些HTTP模块,使其一次合作者处理这个请求。
为了精确地控制超时,还需要把读写事件放置到定时器中。
通过事件模块提东的ngx_handle_read_event方法和ngx_handle_write_event方法,可以把相应的事件添加到epoll中,我们可以起到在满足事件触发条件时,ngxin进程会调用ngx_event_t事件的handler回调方法执行业务。而通过事件模块通过的ngx_add_timer方法可以将上面的读事件或者写事件添加到定时器中,在满足超时条件后,Nginx进程同样会调用调用ngx_event_t事件的Handler回调方法执行业务。
TCP连接建立成功以后,TCP连接上第一次出现可读事件时,将会调用ngx_http_init_request方法初始化这个HTTP请求,HTTP框架并不会在连接建立成功后就开始初始化请求,而是在这个连接的套接字缓冲区傻瓜确实接收到用户发来的请求内容时才进行。
每个HTTP模块都可以针对一个请求设置上下文结构体,并通过ngx_http_set_ctx和ngx_http_get_module_ctx宏来设置和获取上下文,这些HTTP模块针对请求设置的上下文结构体指针,实际上时保存到ngx_http_request_t结构体的ctx指针数组中的。
Ngx_http_core_content_phase是NGX_HTTP_CONTENT_PHASE阶段的checker方法,可以说他是我们开发HTTP模块时最常用的一个阶段,NGX_HTTP_CONTENT_PAHSE阶段用于真正处理请求的内容。其余10个阶段中个HTTP模块的处理方法都是放在全局的ngx_http_core_main_conf_t结构体中的,也就是说,他们对任何一个HTTP请求都是有效的。但在NGX_HTTP_CONTENT_PHASE阶段却是很自然地有另一种需求,有的HTTP模块可能仅今希望在这个处理请求内容的阶段,仅针对某种请求唯一生效,而不是对所有请求生效。例如,仅当请求的URI匹配了配置文件中的某个Locatin块时,再根据Location块下的配置选择一个HTTP模块执行他的Handler处理方法,并以此替代NGX_HTTP_CONTENT_PHASE阶段的其他handler方法(这些handler方法对于该请求将得不到执行),这个方式被设置为ngx_http_core_loc_conf_t中的handler
处理Post请求,调用ngx_http_run_poted_requests方法处理Post请求。
如果一个请求同时需要与多个上游服务器打交道,同时处理多个TCP连接,那么它需要处理的事件就太多了,这种复杂度会使得模块难以维护,通过使用subrequest机制
一个请求通常由必选的HTTP请求行、请求头部、以及可选的包体组成。
Ngx_http_send_header方法负责狗仔HTTP相应行、头部,同时会把他们发送给客户端。他是一个过滤链表,最后一个节点负责发送,就是过滤模块ngx_http_header_filter_modlue提供的ngx_http_header_filter方法则会根据HTTP规则把headers_out中的成员变量序列化为字符流,如果无法一次把相应头发送出去怎么办?这就需要使用ngx_http_request_t结构体中ngx_chain_t类型的成员Out了,它将会保存没有发送完的相应头部,如何发送剩余的相应头部,需要结合结束请求的ngx_http_finalize_request方法来说。
当ngx_http_header_filter方法无法一次性发送HTTP头部时,将会有以下两个现象同时发生,请求的Out成员中将会保存剩余的相应头部,Ngx_http_header_filter方法返回NGX_AGAIN.
如果这个响应没有包体,那么这时通常已经可以调用ngx_http_finalize_request方法来结束请求了,此函数的第二个参数很关键,我们需要把NGX_AGAIN传进去,这样ngx_http_finalize_request方法就理解了实际上还需要HTTP框架继续发送请求Out成员中保存的剩余响应字符流。Ngx_http_finalize_request方法会设置请求的write_event_handler成员为ngx_http_write方法,这样,当连接上有可写事件时,就会调用ngx_http_write方法继续发送剩余的HTTP响应。Ngx_http+finalize_request方法结合第二个参数可以有很多中执行流程。