HTTP 请求的 11 个处理阶段

2015-09-28 12:50:20   最后更新: 2015-09-28 12:50:20   访问数量:855




nginx 将一个 HTTP 请求分为 11 个处理阶段,这样做让每一个 HTTP 模块可以仅仅专注于完成一个独立、简单的功能,而一个请求的完整处理过程可以由多个 HTTP 模块共同合作完成

将一次 HTTP 请求划分为 11 个处理阶段,通过每个阶段内部多个 HTTP 模块流水式的处理请求,可以极大地提高多个模块合作的协同性、可测试性、可扩展性

 

// enum ngx_http_phases // 11 个 HTTP 处理阶段枚举类型 {{{ typedef enum { // 接收到完整 HTTP 头部后处理阶段 NGX_HTTP_POST_READ_PHASE = 0, // 在 URI 与 location 匹配前修改请求的 URI(重定向) NGX_HTTP_SERVER_REWRITE_PHASE, // 根据请求 URI 匹配 location 表达式 // 该阶段只能由 ngx_http_core_module 模块实现 NGX_HTTP_FIND_CONFIG_PHASE, // 匹配 location 后修改请求 URI NGX_HTTP_REWRITE_PHASE, // 防止递归修改 URI 造成死循环 // 该阶段只能由 ngx_http_core_module 模块实现 NGX_HTTP_POST_REWRITE_PHASE, // HTTP 模块介入处理阶段 NGX_HTTP_PREACCESS_PHASE, // nginx 服务器访问限制 // 如果 nginx 不允许访问则返回 NGX_HTTP_FORBIDDEN 或 NGX_HTTP_UNAUTHORIZED NGX_HTTP_ACCESS_PHASE, // 向用户发送拒绝服务的错误响应 NGX_HTTP_POST_ACCESS_PHASE, // 如果 HTTP 请求访问静态文件资源 // try_files 配置项可以使这个请求顺序的访问多个静态文件资源 // 直到某个静态文件资源符合选取条件 NGX_HTTP_TRY_FILES_PHASE, // 处理 HTTP 请求内容,大部分 HTTP 模块会介入该阶段 NGX_HTTP_CONTENT_PHASE, // 处理请求后记录日志 NGX_HTTP_LOG_PHASE } ngx_http_phases; // }}}

 

 

这个枚举类型中枚举了 nginx 定义的所有的 11 个 HTTP 请求处理阶段,有些阶段是必备的,有些阶段是可选的,各个阶段可以允许有多个 HTTP 模块同时介入,nginx 会按照各个 HTTP 模块的 ctx_index 顺序执行这些模块的 handler 方法

但是,NGX_HTTP_FIND_CONFIG_PHASE、NGX_HTTP_POST_REWRITE_PHASE、NGX_HTTP_POST_ACCESS_PHASE、NGX_HTTP_TRY_FILES_PHASE 这四个阶段是不允许 HTTP 模块加入自己的 ngx_http_handler_pt 方法处理用户请求的,他们仅由 HTTP 框架自身实现

 

在 ngx_http_core_main_conf_t 有一个 ngx_http_phase_engine_t 类型的 phase_engine 字段和一个 ngx_http_phase_t 类型的 phases[NGX_HTTP_LOG_PHASE + 1] 数组

他们存储了 HTTP 处理过程中的所有回调函数,其中 phase_engine 控制运行过程中一个 HTTP 请求所要经过的 HTTP 处理阶段,而 phase 数组则仅会在 nginx 启动过程中按照 11 个阶段的概念初始化 phase_engine 中的 handlers 数组

 

// struct ngx_http_phase_engine_t // http 处理引擎,存储所有 ngx_http_phase_handler_t {{{ typedef struct { // 各阶段回调函数结构首地址 ngx_http_phase_handler_t *handlers; // 存储 NGX_HTTP_SERVER_REWRITE_PHASE 阶段第一个回调函数序号,用于快速跳转 ngx_uint_t server_rewrite_index; // 存储 NGX_HTTP_REWRITE_PHASE 阶段第一个毁掉函数序号,用于快速跳转 ngx_uint_t location_rewrite_index; } ngx_http_phase_engine_t; // }}}

 

 

// struct ngx_http_phase_t // http 请求处理各阶段数组,用于初始化 ngx_http_phase_engine_t {{{ typedef struct { ngx_array_t handlers; } ngx_http_phase_t; // }}}

 

 

一般来说,各个 HTTP 模块都是在 postconfiguration 方法中将自定义方法添加到 handler 动态数组中的,这样这个方法在 HTTP 框架初始化过程中最终会被添加到 phase_engine 中

 

正如上面介绍的,各个 HTTP 模块都选择在 postconfiguration 回调函数中将自定义方法添加到 handler 动态数组中,原因是在所有 postconfiguration 回调函数调用前,nginx 执行了 ngx_http_init_phases 初始化 phase 结构,然后在调用所有的 postconfiguration 回调函数以后执行了 ngx_http_init_phase_handlers 为 phase_engine 字段赋值

// static ngx_int_t // ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) // HTTP 处理回调数组初始化 {{{ 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; } // }}}

 

 

// static ngx_int_t // ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) // 将所有的 HTTP 请求处理回调函数加入配置 {{{ 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; ph++; } } return NGX_OK; } // }}}

 

 

这个函数完成了对配置中各个阶段 checker、handler 两个回调函数的赋值

 






技术帖      web      龙潭书斋      open      nginx      server      opensource      sourcecode      http      webserver      code      phase     


京ICP备15018585号