HTTP处理阶段的规则:
对于每个HTTP阶段, 它都包括checker检查方法和handler处理方法
在任意一个ngx_http_phase阶段, 都可以拥有零个或多个ngx_http_phase_handler_t结构体.
一个http{}块解析完后, 就会根据nginx.conf中的配置产生由ngx_http_phase_handler_t组成的数组, 在处理HTTP请求时, 一般情况下这些阶段是顺序向后执行的, 但ngx_http_phase_handler_t结构体中的next成员使得他们可以非顺序执行. ngx_http_phase_engine_t结构体就是所有ngx_http_phase_handler_t组成的数组.
在HTTP框架初始化的过程中, 任何HTTP模块都可以在ngx_http_module_t中的postconfiguration方法中将自定义的方法添加到handler动态数组中, 这样这个方法就会被最终添加到phase_engine中.
从该方法中可以看出, 方法只会调用每个处理阶段的checker方法, 而不会亲自执行每个阶段中的handler方法. 这是因为handler方法仅在checker方法中被执行, checker方法则由HTTP框架提供, 这样就可以控制各个HTTP模块实现的处理方法在不同的阶段采用不同的调用行为.
还可以看出的是, 如果checker方法返回NGX_OK, 那么整个循环就会结束. 这是因为在接收完HTTP头部后, 是很难在一次NGINX框架的调度中处理完成一个请求的. 在第一次接收完HTTP头部后, HTTP框架就调度ngx_http_process_request方法来对请求进行首次业务处理. ngx_http_core_run_phases方法中就是从中摘取出的. 当某个阶段的某个HTTP模块无法在这一次框架调度中完成任务时(对应的checker方法中的ngx_http_handler_pt可能返回NGX_AGAIN, 即表示需要读取更多的数据才能完成), 就不再继续调用HTTP模块的handler进行处理. 继而把控制权交还给NGINX框架, 当这个请求上对应的事件再次触发时, HTTP框架将执行ngx_http_request_handler方法开始继续处理请求而不是首次调用的ngx_http_process_request方法. 在ngx_http_request_handler方法中, 会从ngx_http_process_request方法断开的地方继续处理请求. 这里只是简单的描述, 更详细的以后会有.
下面就针对每个阶段进行了解.
1. NGX_HTTP_POST_READ_PHASE阶段.(可添加HTTP模块)
在接收到完整的HTTP头部后处理的阶段. 任意想要在NGX_HTTP_POST_READ_PHASE阶段处理请求的HTTP模块, 必须首先在ngx_http_core_main_conf_t中的phase[NGX_HTTP_POST_READ_PHASE]动态数组中添加自己实现的ngx_http_handler_pt方法.
对于每个HTTP阶段, 它都包括checker检查方法和handler处理方法
typedef struct ngx_http_phase_handler_s ngx_http_phase_handler_t;
//一个HTTP处理阶段中的checker方法, 仅可以由HTTP框架实现, 以此控制HTTP请求的处理流程.
typedef ngx_int_t (*ngx_http_phase_handler_pt)(ngx_http_request_t *r, ngx_http_phase_handler_t *ph);
//由HTTP模块实现的handler处理方法
typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);
//要注意的是, ngx_http_phase_handler_t结构体仅表示处理阶段中的一个处理方法
struct ngx_http_phase_handler_s{
//在处理到某个HTTP处理阶段时, HTTP框架将会在checker方法已实现的前提下首先调用checker方法来处理请求. 而不会
//直接调用任何阶段中的handler方法, 只有在checker方法中才会去调用handler方法
//因此, 事实上所有的checker方法都是由框架中的ngx_http_core_module模块实现的
//且普通的http模块无法重定义checker方法
ngx_http_phase_handler_pt checker;
//除ngx_http_core_Module模块之外的HTTP模块, 只能通过定义handler方法才能介入某个HTTP处理阶段以处理请求.
ngx_http_handler_pt handler;
//将要执行的下一个HTTP处理阶段的序号
//使用来next就使得处理阶段不必按顺序依次执行了, 既可以向后跳跃多个阶段执行, 也可以跳到之前执行过的阶段重新执行
//通常, next表示下一个处理阶段中第一个ngx_http_phase_handler_t处理方法
ngx_uint_t next;
};
在任意一个ngx_http_phase阶段, 都可以拥有零个或多个ngx_http_phase_handler_t结构体.
一个http{}块解析完后, 就会根据nginx.conf中的配置产生由ngx_http_phase_handler_t组成的数组, 在处理HTTP请求时, 一般情况下这些阶段是顺序向后执行的, 但ngx_http_phase_handler_t结构体中的next成员使得他们可以非顺序执行. ngx_http_phase_engine_t结构体就是所有ngx_http_phase_handler_t组成的数组.
typedef struct {
//这里的handlers表示由ngx_http_phase_handler_t组成的数组, 它表示一个请求可能经历的所有ngx_http_handler_pt处理方法
ngx_http_phase_handler_t *handlers;
//表示NGX_HTTP_SERVER_REWRITE_PHASE阶段第一个ngx_http_phase_handler_t处理方法在handlers中的序号, 用于在执行HTTP请求的任何阶段中快速跳转到NGX_HTTP_SERVER_REWRITE_PHASE阶段处理请求
ngx_uint_t server_rewrite_index;
//表示NGX_HTTP_REWRITE_PHASE阶段第一个ngx_http_phase_handler_t处理方法在handlers中的序号, 用于在执行HTTP请求的任何阶段中快速跳转到NGX_HTTP_REWRITE_PHASE阶段处理请求
ngx_uint_t location_rewrite_index;
}ngx_http_phase_engine_t;
可见, 此结构体中保存来在当前nginx.conf下一个用户请求可能经历的所有ngx_http_handler_pt处理方法, 这个结构体是保存在全局的ngx_http_core_main_conf_t结构体中的
typedef struct {
ngx_http_phase_engine_t phase_engine;
ngx_http_phase_t phase[NGX_HTTP_LOG_PHASE+1];
...
}ngx_http_core_main_conf_t;
这里的phase_engine成员控制运行过程中一个HTTP请求所要经过的HTTP处理阶段, 它将配合ngx_http_request_t结构体中的phase_handler成员使用(该成员指定了当前请求应当执行哪一个HTTP阶段)
在HTTP框架初始化的过程中, 任何HTTP模块都可以在ngx_http_module_t中的postconfiguration方法中将自定义的方法添加到handler动态数组中, 这样这个方法就会被最终添加到phase_engine中.
各阶段checker方法分析
下面先看一下各个阶段. 在11个阶段中有7个阶段是允许各个HTTP模块向阶段中任意添加自己实现的handler方法的.同一个阶段的所有handler方法都拥有相同的checker方法. 且每个阶段中的处理方法的返回值都会以不同的方式影响HTTP框架的行为. 下面是HTTP框架在首次从业务上处理请求方法中调用的ngx_http_core_run_phases方法.
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;
while (ph[r->phase_handler].checker) {
rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
if (rc == NGX_OK) {
return;
}
}
}
(此方法在上面对各个结构体的介绍过后显得十分容易理解. 就是循环调用每个阶段的checker方法, 因此没作注释)
从该方法中可以看出, 方法只会调用每个处理阶段的checker方法, 而不会亲自执行每个阶段中的handler方法. 这是因为handler方法仅在checker方法中被执行, checker方法则由HTTP框架提供, 这样就可以控制各个HTTP模块实现的处理方法在不同的阶段采用不同的调用行为.
还可以看出的是, 如果checker方法返回NGX_OK, 那么整个循环就会结束. 这是因为在接收完HTTP头部后, 是很难在一次NGINX框架的调度中处理完成一个请求的. 在第一次接收完HTTP头部后, HTTP框架就调度ngx_http_process_request方法来对请求进行首次业务处理. ngx_http_core_run_phases方法中就是从中摘取出的. 当某个阶段的某个HTTP模块无法在这一次框架调度中完成任务时(对应的checker方法中的ngx_http_handler_pt可能返回NGX_AGAIN, 即表示需要读取更多的数据才能完成), 就不再继续调用HTTP模块的handler进行处理. 继而把控制权交还给NGINX框架, 当这个请求上对应的事件再次触发时, HTTP框架将执行ngx_http_request_handler方法开始继续处理请求而不是首次调用的ngx_http_process_request方法. 在ngx_http_request_handler方法中, 会从ngx_http_process_request方法断开的地方继续处理请求. 这里只是简单的描述, 更详细的以后会有.
下面就针对每个阶段进行了解.
1. NGX_HTTP_POST_READ_PHASE阶段.(可添加HTTP模块)
在接收到完整的HTTP头部后处理的阶段. 任意想要在NGX_HTTP_POST_READ_PHASE阶段处理请求的HTTP模块, 必须首先在ngx_http_core_main_conf_t中的phase[NGX_HTTP_POST_READ_PHASE]动态数组中添加自己实现的ngx_http_handler_pt方法.