关闭

nginx的十一个阶段处理

标签: nginx阶段
4794人阅读 评论(0) 收藏 举报
分类:

   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:终止阶段函数回调调用。

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:18820次
    • 积分:161
    • 等级:
    • 排名:千里之外
    • 原创:14篇
    • 转载:2篇
    • 译文:0篇
    • 评论:0条
    文章分类