您的位置:首页 > 运维架构 > Nginx

nginx的十一个阶段处理

2014-04-19 00:46 661 查看
nginx的源码确实比较难读,怎么说呢, 一大堆的函数回调指针,没有理清脉络,看源码就很费劲。

首先要弄清楚的就是要理顺nginx调用的主框架,nginx是以配置为中心的处理架构,想读懂,先了解配置。

言归正传,这里说nginx处理的是一个阶段,

typedef enum {
NGX_HTTP_POST_READ_PHASE = 0,   //读取请求头

NGX_HTTP_SERVER_REWRITE_PHASE,   //执行rewrite

NGX_HTTP_FIND_CONFIG_PHASE,  //根据uri替换location
NGX_HTTP_REWRITE_PHASE,      //根据替换结果继续执行rewrite
NGX_HTTP_POST_REWRITE_PHASE, //执行rewrite后处理

NGX_HTTP_PREACCESS_PHASE,    //认证预处理   请求限制,连接限制

NGX_HTTP_ACCESS_PHASE,       //认证处理
NGX_HTTP_POST_ACCESS_PHASE,  //认证后处理, 认证不通过, 丢包

NGX_HTTP_TRY_FILES_PHASE,    //尝试try标签
NGX_HTTP_CONTENT_PHASE,      //内容处理

NGX_HTTP_LOG_PHASE           //日志处理
} ngx_http_phases;


以上每个阶段的处理都是一个数组回调。数据的初始化如下:

static ngx_int_t
ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
{
if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers,
cf->pool, 1, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}

if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers,
cf->pool, 1, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}

if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
cf->pool, 1, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}

if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers,
cf->pool, 1, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}

if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers,
cf->pool, 2, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}

if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers,
cf->pool, 4, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}

if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers,
cf->pool, 1, sizeof(ngx_http_handler_pt))
!= NGX_OK)
{
return NGX_ERROR;
}

return NGX_OK;
}


可以看到

NGX_HTTP_FIND_CONFIG_PHASE,  //根据uri替换location
NGX_HTTP_POST_REWRITE_PHASE, //执行rewrite后处理
NGX_HTTP_POST_ACCESS_PHASE,  //认证后处理, 认证不通过, 丢包


以上几个阶段都没有做数组的初始化化。

还要说一点的是,真正执行的时候,并不是调用cmcf->phases处理的, 而是调用cmcf->phase_engine.handlers
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不为NGX_OK就继续执行。
return;
}
}
}


phase_engine的初始化如下
static ngx_int_t
ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
{
ngx_int_t                   j;
ngx_uint_t                  i, n;
ngx_uint_t                  find_config_index, use_rewrite, use_access;
ngx_http_handler_pt        *h;
ngx_http_phase_handler_t   *ph;
ngx_http_phase_handler_pt   checker;

cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1;
cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1;
find_config_index = 0;
use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;
use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;

n = use_rewrite + use_access + cmcf->try_files + 1 /* find config phase */;

for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
n += cmcf->phases[i].handlers.nelts;
}

ph = ngx_pcalloc(cf->pool,
n * sizeof(ngx_http_phase_handler_t) + sizeof(void *));
if (ph == NULL) {
return NGX_ERROR;
}

cmcf->phase_engine.handlers = ph;
n = 0;

for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
h = cmcf->phases[i].handlers.elts;

switch (i) {

case NGX_HTTP_SERVER_REWRITE_PHASE:
if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) {
cmcf->phase_engine.server_rewrite_index = n;
}
checker = ngx_http_core_rewrite_phase;

break;

case NGX_HTTP_FIND_CONFIG_PHASE:
find_config_index = n;

ph->checker = ngx_http_core_find_config_phase;
n++;
ph++;

continue;

case NGX_HTTP_REWRITE_PHASE:
if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) {
cmcf->phase_engine.location_rewrite_index = n;
}
checker = ngx_http_core_rewrite_phase;

break;

case NGX_HTTP_POST_REWRITE_PHASE:
if (use_rewrite) {
ph->checker = ngx_http_core_post_rewrite_phase;
ph->next = find_config_index;
n++;
ph++;
}

continue;

case NGX_HTTP_ACCESS_PHASE:
checker = ngx_http_core_access_phase;
n++;
break;

case NGX_HTTP_POST_ACCESS_PHASE:
if (use_access) {
ph->checker = ngx_http_core_post_access_phase;
ph->next = n;
ph++;
}

continue;

case NGX_HTTP_TRY_FILES_PHASE:
if (cmcf->try_files) {
ph->checker = ngx_http_core_try_files_phase;
n++;
ph++;
}

continue;

case NGX_HTTP_CONTENT_PHASE:
checker = ngx_http_core_content_phase;
break;

default:
checker = ngx_http_core_generic_phase;
}

n += cmcf->phases[i].handlers.nelts;

for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) {
ph->checker = checker;
ph->handler = h[j];  //数组是反向赋值的,刚好对应了数组操作的顺序
ph->next = n;        //next永远执行下一个阶段的执行索引
ph++;
}
}

return NGX_OK;
}


从上面可以看到,nginx把所有阶段的回调函数组成了一个串行的执行函数数组。
cheker指针指向检测调用函数指针,hander指向该阶段的函数调用指针,next则指向下一阶段的ph索引。
当执行某一阶段到一半的时候,想跳到下一个阶段,只需要r->phase_handler = ph->next;

ph的返回值为NGX_OK时, 函数会跳出阶段的执行,但是在阶段执行的hander中却不是这样的。

NGX_DECLINED: 会直接执行下一个ph调用。

NGX_AGAIN: 会重复调用本ph

NGX_DOWN:终止阶段函数回调调用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: