nginx源码分析(8)——phase handler处理

来源:互联网 发布:在淘宝买电脑可靠吗 编辑:程序博客网 时间:2024/05/23 15:06

        nginx将请求的处理过程划分为11个phase(阶段),相当于是对请求处理的一种抽象,便于定制处理过程。这个11个phase,分别是(定义在http/ngx_http_core_module.h):

typedef enum {    NGX_HTTP_POST_READ_PHASE = 0,    /* 读取请求 */    NGX_HTTP_SERVER_REWRITE_PHASE,   /* server级别的rewrite */    NGX_HTTP_FIND_CONFIG_PHASE,     /* 根据uri查找location */    NGX_HTTP_REWRITE_PHASE,          /* localtion级别的rewrite */    NGX_HTTP_POST_REWRITE_PHASE,     /* server、location级别的rewrite都是在这个phase进行收尾工作的 */    NGX_HTTP_PREACCESS_PHASE,        /* 粗粒度的access */    NGX_HTTP_ACCESS_PHASE,           /* 细粒度的access,比如权限验证、存取控制 */    NGX_HTTP_POST_ACCESS_PHASE,     /* 根据上述两个phase得到access code进行操作 */    NGX_HTTP_TRY_FILES_PHASE,        /* 实现try_files指令 */    NGX_HTTP_CONTENT_PHASE,          /* 生成http响应 */    NGX_HTTP_LOG_PHASE               /* log模块 */} ngx_http_phases;
        这些phase按照先后顺序执行,只有在rewrite之后流程会重新跳转到NGX_HTTP_FIND_CONFIG_PHASE。其中,只有7个phase可以注册handler以定制处理过程,其他的只有一个固定的handler:

NGX_HTTP_POST_READ_PHASE   NGX_HTTP_SERVER_REWRITE_PHASE,  NGX_HTTP_REWRITE_PHASE,  NGX_HTTP_PREACCESS_PHASE,  NGX_HTTP_ACCESS_PHASE,  NGX_HTTP_CONTENT_PHASE,  NGX_HTTP_LOG_PHASE
        一般地,phase handler的注册都是在http模块的postconfiguration回调函数中,后面会看到为什么要在这个时间点注册。

1. 重要的数据结构

        1. ngx_http_phase_t

typedef struct {    ngx_array_t                handlers;} ngx_http_phase_t;

        ngx_http_core_main_conf_t的phases数组存放了所有的phase,其中每个元素是ngx_http_phase_t类型的,表示的就是对应的phase handler的数组。ngx_http_core_main_conf_t->phases数组主要用于handler的注册。

        2. ngx_http_phase_engine_t

typedef struct {    /**     * 所有phase handler的数组。     */    ngx_http_phase_handler_t  *handlers;    /**     * server rewrite阶段的handler在ngx_http_core_main_conf_t->phase_engine.handlers数组中的下标     */    ngx_uint_t                 server_rewrite_index;    /**     * rewrite阶段的handler在ngx_http_core_main_conf_t->phase_engine.handlers数组中的下标     */    ngx_uint_t                 location_rewrite_index;} ngx_http_phase_engine_t;
        ngx_http_core_main_conf_t的phase_engine字段表示phase的执行引擎,它会把所有的phase handler组织成数组,元素是ngx_http_phase_handler_t。phase_engine会根据phases数组中注册的handler进行初始化。

        3. ngx_http_phase_handler_t
struct ngx_http_phase_handler_s {    /* 执行校验,并调用handler函数,同一个phase的handler的checker相同 */    ngx_http_phase_handler_pt  checker;    /* handler函数指针 */    ngx_http_handler_pt        handler;    /*     * 指向下一个phase的第一个handler在ngx_http_core_main_conf_t->phase_engine.handlers数组中的下标     *     */    ngx_uint_t                 next;};
        

2. phase handler初始化

        phase handler初始化是在http模块初始化函数ngx_http_block中完成的,摘录关键代码:
    /**     * 初始化每个phase对应的handlers数组,以便在执行postconfiguration回调函数时,     * 注册phase handler。     * ngx_http_core_main_conf_t->phases数组存放所有的phase。     */    if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {        return NGX_CONF_ERROR;    }    if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {        return NGX_CONF_ERROR;    }    for (m = 0; ngx_modules[m]; m++) {        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {            continue;        }        module = ngx_modules[m]->ctx;        if (module->postconfiguration) {            if (module->postconfiguration(cf) != NGX_OK) {                return NGX_CONF_ERROR;            }        }    }    if (ngx_http_variables_init_vars(cf) != NGX_OK) {        return NGX_CONF_ERROR;    }    /*     * http{}'s cf->ctx was needed while the configuration merging     * and in postconfiguration process     */    *cf = pcf;    /**     * 根据各个phase的handlers数组初始化ngx_http_core_main_conf_t->phase_engine。     * 在phase_engine中所有的handler存放在一个数组中。     */    if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {        return NGX_CONF_ERROR;    }
        先调用ngx_http_init_phases为ngx_http_core_main_conf_t->phases分配空间,然后会调用所有http module的postconfiguration回调函数,最后再调用ngx_http_init_phase_handlers初始化ngx_http_core_main_conf_t->phase_engine。这就是为什么phase handler的注册只能在postconfiguration回调函数中,因为只有在它调用前phases才会分配空间。ngx_http_init_phases函数很简单,就是一堆ngx_array_t的初始化,下面看一下ngx_http_init_phase_handlers。
1. ngx_http_init_phase_handlers
static ngx_int_tngx_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;    /* ngx_http_rewrite在http module的postconfiguration回调函数中添加REWRITE阶段的处理函数 */    use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;    /* ngx_http_access在http module的postconfiguration回调函数中添加ACCESS阶段的处理函数 */    use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;    /* 计算handler数组的大小 */    n = use_rewrite + use_access + cmcf->try_files + 1 /* find config phase */;    /* 对所有handlers计数 */    for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {        n += cmcf->phases[i].handlers.nelts;    }    /* 为handler数组分配内存 */    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;    /* 下一个phase的第一个handler的索引 */    n = 0;    /*     * 初始化phase handler,保存checker和next字段     * continue的都是不能添加handler的phase     */    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) {            /* 设置server rewrite对应的handler的开始下标 */                cmcf->phase_engine.server_rewrite_index = n;            }            checker = ngx_http_core_rewrite_phase;            break;        case NGX_HTTP_FIND_CONFIG_PHASE:        /* find config对应的handler的下标,后面post rewrite的handler设置需要用到 */            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) {            /* 设置location rewrite的handler的开始下标 */                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;                /**                 * 这里将post rewrite的next设置为find config的handler对应下标。                 * 因为在location rewrite之后,需要重新匹配location,所以需要再次                 * 进入这个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;        }        /* 跳过本phase所有handler,也就指向了下一个phase的第一个handler */        n += cmcf->phases[i].handlers.nelts;        /* 遍历初始化同一个phase上的handler */        for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) {            ph->checker = checker;            ph->handler = h[j];            ph->next = n;            ph++;        }    }    return NGX_OK;}

        具体可以参见注释。大致原理就是将所有的phase handler以ngx_http_phase_handler_t->next组织成handler链表,处理请求时遍历这个链表。handler处理函数ngx_http_phase_handler_t->handler的调用是在checker中完成的,不同的phase具有不同的checker,但是同一个phase的checker相同。调用完这个函数,phase handler的初始化就完成了,下面看一下handler的调用。

3. phase handler调用

        在请求处理一文中介绍了在处理的最后一步就是调用ngx_http_core_run_phases跑一遍所有的phase handler,下面看一下这个函数。

voidngx_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;    /* 遍历phase上注册的所有handler,这里是以r->phase_handler为索引组成的链表 */    while (ph[r->phase_handler].checker) {        rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);        /* 如果一个checker返回ok,则后面的handler不会被调用 */        if (rc == NGX_OK) {            return;        }    }}
        ngx_http_core_run_phases会遍历所有的phase,然后调用它的checker进行处理,phase处理过程中的错误处理,校验等都是在checker中完成的,不同phase的checker的逻辑是不同,但是返回值的意义是相同的,如果checker的返回值时NGX_OK表示请求处理完毕,否则会进入下一个handler继续处理。接下来看一下phase的checker。

4. phase handler的checker

        由于checker的返回值决定了是否执行下一个handler,而且handler的返回值又决定了checker的返回值,所以在编写phase handler时,要特别注意返回值。

1. ngx_http_core_generic_phase

        这个checker用于处理post read和preaccess两个phase。它的作用很简单,就是根据handler的返回值决定继续这个phase的handler的处理,还是调用下一个phase的handler。它的返回值分为四种:
        NGX_OK:本phase处理完毕,可以继续执行下一个phase的handler,返回NGX_AGAIN。
        NGX_DECLINED:handler由于某种原因执行失败,但不影响本phase其他handler的执行,所以继续执行本phase的其他handler,返回NGX_AGAIN。
        NGX_AGAIN或者NGX_DONE:请求处理完毕,返回NGX_OK。
        NGX_ERROR或其他错误:终结请求的处理,释放相关资源。
ngx_int_tngx_http_core_generic_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph){    ngx_int_t  rc;    /*     * generic phase checker,     * used by the post read and pre-access phases     */    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                   "generic phase: %ui", r->phase_handler);    rc = ph->handler(r);    /* phase处理完毕,将r->phase_handler指向下一个phase的第一个handler */    if (rc == NGX_OK) {        r->phase_handler = ph->next;        return NGX_AGAIN;    }    /* 继续处理本phase。handler因为某种原因没有执行,继续执行其他的handler */    if (rc == NGX_DECLINED) {        r->phase_handler++;        return NGX_AGAIN;    }    /* 整个请求处理完毕 */    if (rc == NGX_AGAIN || rc == NGX_DONE) {        return NGX_OK;    }    /* rc == NGX_ERROR || rc == NGX_HTTP_...  */    ngx_http_finalize_request(r, rc);    return NGX_OK;}

2. ngx_http_core_find_config_phase

        这是find config phase的checker,用于根据uri查找对应的location,nginx中location的处理是相当复杂的,这里关注于phase handler的处理流程。find config phase只有一个phase handler,并且它没有相应的handler回调函数,完成的只是根据uri匹配到location之后,将location的loc_conf赋值给request,并且根据loc_conf对request进行一些处理。所有的由静态字符串标识的location被称作static location,由正则表达式表示的location成为regex location。所有的static location被组织成二叉树,以便于查找。在static location匹配失败后,会进行regex location匹配。这个过程正好描述了nginx中location的匹配规则。
        find config的checker可能会被执行多次,当rewrite成功后,会修改uri参数,需要重新匹配location。这就是find_config_index存在的必要,它用于初始化post rewrite phase handler的next字段,当uri被修改后会重新跳至find config phase执行。
ngx_int_tngx_http_core_find_config_phase(ngx_http_request_t *r,    ngx_http_phase_handler_t *ph){    u_char                    *p;    size_t                     len;    ngx_int_t                  rc;    ngx_http_core_loc_conf_t  *clcf;    r->content_handler = NULL;    r->uri_changed = 0;    /* 根据uri查找location,先静态查找,再正则匹配 */    rc = ngx_http_core_find_location(r);    if (rc == NGX_ERROR) {        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);        return NGX_OK;    }    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);    /* 非内部请求访问内部location是非法的,所有与error处理类似 */    if (!r->internal && clcf->internal) {        ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);        return NGX_OK;    }    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                   "using configuration \"%s%V\"",                   (clcf->noname ? "*" : (clcf->exact_match ? "=" : "")),                   &clcf->name);    /* 根据匹配的location设置request的属性 */    ngx_http_update_location_config(r);    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                   "http cl:%O max:%O",                   r->headers_in.content_length_n, clcf->client_max_body_size);    /* 判断请求内容大小是否超过限制 */    if (r->headers_in.content_length_n != -1        && !r->discard_body        && clcf->client_max_body_size        && clcf->client_max_body_size < r->headers_in.content_length_n)    {        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,                      "client intended to send too large body: %O bytes",                      r->headers_in.content_length_n);        (void) ngx_http_discard_request_body(r);        ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE);        return NGX_OK;    }    /* 处理重定向 */    if (rc == NGX_DONE) {        r->headers_out.location = ngx_list_push(&r->headers_out.headers);        if (r->headers_out.location == NULL) {            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);            return NGX_OK;        }        /*         * we do not need to set the r->headers_out.location->hash and         * r->headers_out.location->key fields         */        if (r->args.len == 0) {            r->headers_out.location->value = clcf->name;        } else {            len = clcf->name.len + 1 + r->args.len;            p = ngx_pnalloc(r->pool, len);            if (p == NULL) {                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);                return NGX_OK;            }            r->headers_out.location->value.len = len;            r->headers_out.location->value.data = p;            p = ngx_cpymem(p, clcf->name.data, clcf->name.len);            *p++ = '?';            ngx_memcpy(p, r->args.data, r->args.len);        }        ngx_http_finalize_request(r, NGX_HTTP_MOVED_PERMANENTLY);        return NGX_OK;    }    /* 执行rewrite phase handler */    r->phase_handler++;    return NGX_AGAIN;}

3. ngx_http_core_rewrite_phase

        用于处理server rewrite phase和rewrite phase。逻辑很简单就是执行响应的handler,因为phase handler执行流程的跳转是在post rewrite中完成的,所以这里只需要将r->phase_handler++顺序遍历其后的handler即可。
ngx_int_tngx_http_core_rewrite_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph){    ngx_int_t  rc;    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                   "rewrite phase: %ui", r->phase_handler);    rc = ph->handler(r);    /* 继续处理本phase的handler */    if (rc == NGX_DECLINED) {        r->phase_handler++;        return NGX_AGAIN;    }    /* 请求处理完毕 */    if (rc == NGX_DONE) {        return NGX_OK;    }    /* NGX_OK, NGX_AGAIN, NGX_ERROR, NGX_HTTP_...  */    ngx_http_finalize_request(r, rc);    return NGX_OK;}

4. ngx_http_core_post_rewrite_phase

        这是post rewrite phase的checker,用于对rewrite和server rewrite phase进行收尾工作。request中有两个字段与重写相关:
        uri_changed:uri是否被重写。
        uri_changes:uri被重写的次数,初始值为11,所以只能重写10次。
        server rewrite和rewrite的handler会修改这两个变量,实现重写。这个checker就是根据uri_changed判断是否进入find config phase,然后再根据uri_changes做一些校验。
ngx_int_tngx_http_core_post_rewrite_phase(ngx_http_request_t *r,    ngx_http_phase_handler_t *ph){    ngx_http_core_srv_conf_t  *cscf;    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                   "post rewrite phase: %ui", r->phase_handler);    /**     * uri_changed标志位表示uri是否有被重写。     * 如果没有的话,这里累加r->phase_handler,由于post rewrite只有一个handler,     * 所以就会跳到下一个phase继续执行。     */    if (!r->uri_changed) {        r->phase_handler++;        return NGX_AGAIN;    }    /* uri被重写 */    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                   "uri changes: %d", r->uri_changes);    /*     * gcc before 3.3 compiles the broken code for     *     if (r->uri_changes-- == 0)     * if the r->uri_changes is defined as     *     unsigned  uri_changes:4     */    r->uri_changes--;    /* 校验是否被重写了多次,uri_changes初始值为11,所以最多可以重写10次 */    if (r->uri_changes == 0) {        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,                      "rewrite or internal redirection cycle "                      "while processing \"%V\"", &r->uri);        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);        return NGX_OK;    }    /*      * 在ngx_http_init_phase_handlers中,如果use_rewrite不为0,那么     * post rewrite phase handler的next指向find config的phase handler。     * 接下来会进入find config phase     */    r->phase_handler = ph->next;    /* server rewrite有可能改变了server config,所以要对r->loc_conf重新赋值 */    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);    r->loc_conf = cscf->ctx->loc_conf;    return NGX_AGAIN;}

5. ngx_http_core_access_phase

        这是access phase的checker,逻辑和之前的checker差不多,但需要注意这个checker有自己特有的逻辑:
        satisfy:对应于satisfy指令,‘satisfy all’要满足所有的access handler,‘satisfy any’只需要满足任意一个access handler。
        access_code:access phase中只判断是否有权限,而处理是在post access phase中完成的。access handler中设置具体的access code,然后传递给post access handler,由它处理最终的响应结果。
ngx_int_tngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph){    ngx_int_t                  rc;    ngx_http_core_loc_conf_t  *clcf;    /* 只针对主请求处理 */    if (r != r->main) {        r->phase_handler = ph->next;        return NGX_AGAIN;    }    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                   "access phase: %ui", r->phase_handler);    rc = ph->handler(r);    /* 跳到本phase的下一个handler */    if (rc == NGX_DECLINED) {        r->phase_handler++;        return NGX_AGAIN;    }    /* 请求处理完毕 */    if (rc == NGX_AGAIN || rc == NGX_DONE) {        return NGX_OK;    }    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);    /* 相当于satisfy all,就是必须满足所有条件,所以继续执行access handler */    if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {        if (rc == NGX_OK) {            r->phase_handler++;            return NGX_AGAIN;        }    /* 否则只要满足任意一个条件即可,所以执行下一个phase的第一个handler */    } else {        if (rc == NGX_OK) {        /* 对access_code清零,后面post access phase根据这个属性处理 */            r->access_code = 0;            if (r->headers_out.www_authenticate) {                r->headers_out.www_authenticate->hash = 0;            }            r->phase_handler = ph->next;            return NGX_AGAIN;        }        if (rc == NGX_HTTP_FORBIDDEN || rc == NGX_HTTP_UNAUTHORIZED) {        /* 设置access_code,如果多个handler校验不通过,则只记录最后一个 */            r->access_code = rc;            r->phase_handler++;            return NGX_AGAIN;        }    }    /* rc == NGX_ERROR || rc == NGX_HTTP_...  */    ngx_http_finalize_request(r, rc);    return NGX_OK;}

6. ngx_http_core_post_access_phase

        这个是post access phase的checker,用于对access phase做收尾处理。在ngx_http_init_phase_handlers中只有当use_access为1时这个phase才会有handler,也就是说只有在access phase注册了handler时这个phase才会添加到请求处理流程里。post access handler完成的工作很简单,就是根据access_code做些出。
ngx_int_tngx_http_core_post_access_phase(ngx_http_request_t *r,    ngx_http_phase_handler_t *ph){    ngx_int_t  access_code;    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                   "post access phase: %ui", r->phase_handler);    access_code = r->access_code;    /* 设置了access_code,说明没有权限,则终结请求 */    if (access_code) {        if (access_code == NGX_HTTP_FORBIDDEN) {            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,                          "access forbidden by rule");        }        r->access_code = 0;        ngx_http_finalize_request(r, access_code);        return NGX_OK;    }    /* 否则,跳到下一个handler */    r->phase_handler++;    return NGX_AGAIN;}

7. ngx_http_core_content_phase

        这个checker处理content phase,也就是用于生成响应内容的,我们编写的模块大部分是在这个phase执行的。这个需要注意一点,如果location设置了handler(就是content handler),那么就只会执行这一个handler,而不会执行其他的。大部分content handler中会调用output filter产生输出。content handler的返回值只有等于NGX_DECLINED时才会执行接下来的handler,而如果是其他值则返回NGX_OK,结束请求的处理。
ngx_int_tngx_http_core_content_phase(ngx_http_request_t *r,    ngx_http_phase_handler_t *ph){    size_t     root;    ngx_int_t  rc;    ngx_str_t  path;    /*     * 在find config phase中如果匹配到的location具有handler,则会赋值给r->content_handler。     * 而这里可以看到,如果r->content_handler存在则只会执行这一个handler,然后返回。     * 也就是说如果location设置了handler,则只会执行这一个content handler,不会执行其他的。     */    if (r->content_handler) {        r->write_event_handler = ngx_http_request_empty_handler;        ngx_http_finalize_request(r, r->content_handler(r));        return NGX_OK;    }    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,                   "content phase: %ui", r->phase_handler);    rc = ph->handler(r);    if (rc != NGX_DECLINED) {        ngx_http_finalize_request(r, rc);        return NGX_OK;    }    /* handler返回NGX_DECLINED会由接下来的content handler继续处理 */    /* rc == NGX_DECLINED */    ph++;    /* 如果下一个handler的checker存在,则返回NGX_AGAIN,继续调用下一个handler */    if (ph->checker) {        r->phase_handler++;        return NGX_AGAIN;    }    /* no content handler was found */    if (r->uri.data[r->uri.len - 1] == '/') {        if (ngx_http_map_uri_to_path(r, &path, &root, 0) != NULL) {            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,                          "directory index of \"%s\" is forbidden", path.data);        }        ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN);        return NGX_OK;    }    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no handler found");    ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);    return NGX_OK;}
        这一篇介绍请求处理,下一篇我们来看看响应内容是如何输出的。

原创粉丝点击