nginx十一个阶段处理详解

发布时间:2020-10-04编辑:脚本学堂
本文介绍了nginx中的11个阶段,首先要弄清楚的就是要理顺nginx调用的主框架,nginx是以配置为中心的处理架构,想读懂,先了解配置,感兴趣的朋友参考下。

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