目录

一、HTTP模块11个阶段处理

二、阶段处理的初始化ngx_http_block

三、阶段处理过程ngx_http_core_run_phases

四、挂载自定义模块

上一章我们讲解了HTTP request的解析过程。我们基本知道了Nginx是如何解析HTTP的行和头。

这一章我们主要讲解Nginx的阶段处理(PHASE 状态机实现)。阶段处理的概念如何理解,我举个例子:一个HTTP请求过来,除了解析HTTP的行和头外,还需要解析URI的rewrite、接受HTTP BODY中的POST数据、转发给后端JAVA/PHP服务器进行数据处理等等一系列的操作。

Nginx的PHASE阶段处理共包含11部分,通过这11个阶段的处理,就能完整的处理一个HTTP请求了。

一、HTTP模块11个阶段处理

typedef enum {NGX_HTTP_POST_READ_PHASE = 0, /* 读取请求内容阶段 */NGX_HTTP_SERVER_REWRITE_PHASE, /* Server请求地址重写阶段 */NGX_HTTP_FIND_CONFIG_PHASE, /* 配置查找阶段 */NGX_HTTP_REWRITE_PHASE,  /* Location请求地址重写阶段 */NGX_HTTP_POST_REWRITE_PHASE, /* 请求地址重写提交阶段 */NGX_HTTP_PREACCESS_PHASE,  /* 访问权限检查准备阶段 */NGX_HTTP_ACCESS_PHASE,  /* 访问权限检查阶段 */NGX_HTTP_POST_ACCESS_PHASE,  /* 访问权限检查提交阶段 */NGX_HTTP_TRY_FILES_PHASE,   /* 配置项try_files处理阶段 */NGX_HTTP_CONTENT_PHASE,    /* 内容产生阶段 */NGX_HTTP_LOG_PHASE  /* 日志模块处理阶段 */
} ngx_http_phases;

四个phase是不支持添加http功能的handler的,这四个阶段分别是NGX_FIND_CONFIG_PHASE、NGX_POST_REWRITE_PHASE、NGX_POST_ACCESS_PHASE、NGX_TRY_FILES_PHASE
如果需要自定义添加模块挂载的Nginx的阶段处理上,推荐挂载到这三个阶段:NGX_HTTP_PREACCESS_PHASE、NGX_HTTP_ACCESS_PHASE、NGX_HTTP_CONTENT_PHASE
 
二、阶段处理的初始化ngx_http_block
我们从前面的篇章中知道,HTTP模块的初始化从 ngx_http_block这个方法开始。阶段处理的初始化也在这个方法中。

/***ngx_http_commands 命令集的回调函数*HTTP模块初始化的入口函数**/
static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
........./* 初始化阶段数组 只有这里面的6个阶段可以挂载模块 */if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {return NGX_CONF_ERROR;}
......../*** 初始化阶段处理*/if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {return NGX_CONF_ERROR;}
}

ngx_http_init_phases 初始化阶段数组

/*** 初始化阶段处理数组* 每一个可以挂载模块的阶段,都定义了一个cmcf->phases[?].handlers的数组* 每个阶段被调用的时候,都会去遍历改阶段处理数组下需要处理的逻辑函数*/
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_init_phase_handlers 初始化阶段处理

/*** 初始化阶段处理** nginx在接收并解析完请求行,请求头之后,就会依次调用各个phase handler**   NGX_HTTP_POST_READ_PHASE    读取请求内容阶段NGX_HTTP_SERVER_REWRITE_PHASE   Server请求地址重写阶段NGX_HTTP_FIND_CONFIG_PHASE    配置查找阶段NGX_HTTP_REWRITE_PHASE    Location请求地址重写阶段NGX_HTTP_POST_REWRITE_PHASE 请求地址重写提交阶段NGX_HTTP_PREACCESS_PHASE  访问权限检查准备阶段NGX_HTTP_ACCESS_PHASE 访问权限检查阶段NGX_HTTP_POST_ACCESS_PHASE  访问权限检查提交阶段NGX_HTTP_TRY_FILES_PHASE  配置项try_files处理阶段NGX_HTTP_CONTENT_PHASE  内容产生阶段NGX_HTTP_LOG_PHASE    日志模块处理阶段*/
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) {/* server中的rewrite*/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;/* 根据URI查找 location */case NGX_HTTP_FIND_CONFIG_PHASE:find_config_index = n;ph->checker = ngx_http_core_find_config_phase;n++;ph++;continue;/* localtion级别的rewrite */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;/* server、location级别的rewrite都是在这个phase进行收尾工作的 */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;/* 细粒度的access,比如权限验证、存取控制 */case NGX_HTTP_ACCESS_PHASE:checker = ngx_http_core_access_phase;n++;break;/* 根据上述两个phase得到access code进行操作 */case NGX_HTTP_POST_ACCESS_PHASE:if (use_access) {ph->checker = ngx_http_core_post_access_phase;ph->next = n;ph++;}continue;/* 实现try_files指令 */case NGX_HTTP_TRY_FILES_PHASE:if (cmcf->try_files) {ph->checker = ngx_http_core_try_files_phase;n++;ph++;}continue;/* 生成http响应 */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;
}

三、阶段处理过程ngx_http_core_run_phases
阶段处理核心函数ngx_http_core_run_phases

先看下阶段处理返回的几个状态含义:
NGX_OK:    表示该阶段已经处理完成,需要转入下一个阶段;
NGX_DECLINED:    表示需要转入本阶段的下一个handler继续处理;
NGX_AGAIN, NGX_DONE:表示需要等待某个事件发生才能继续处理(比如等待网络IO),此时Nginx为了不阻塞其他请求的处理,必须中断当前请求的执行链,等待事件发生之后继续执行该handler;
NGX_ERROR:    表示发生了错误,需要结束该请求。

/*** 11个阶段处理HTTP请求*/
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;/* 遍历解析和处理各个阶段的HTTP请求 如果返回rc==NGX_AGAIN 则交由下一个阶段处理;返回OK则返回结果  */while (ph[r->phase_handler].checker) {rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);if (rc == NGX_OK) {return;}}
}/*** 内容接收阶段*/
ngx_int_t
ngx_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);/* handler 回调函数*/rc = ph->handler(r);/* 本阶段处理完成,跳转到下一个阶段处理 */if (rc == NGX_OK) {r->phase_handler = ph->next;return NGX_AGAIN;}/* 本阶段当前的回调函数处理完成,继续执行本阶段其他回调函数 */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;
}

四、挂载自定义模块
Nginx的自定义模块在http/modules/目录下。如果你编写了一个模块,并且想在阶段处理中,编写自己的模块,那么就非常简单了。只要在模块init初始化的时候,将回调函数注册到阶段上,就能实现自定义阶段处理拦截。

我们看下ngx_http_static_module.c模块的阶段处理的注册。

/*** 模块初始化*/
static ngx_int_t
ngx_http_static_init(ngx_conf_t *cf)
{ngx_http_handler_pt        *h;ngx_http_core_main_conf_t  *cmcf;cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);/* 注册到NGX_HTTP_CONTENT_PHASE阶段 */h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);if (h == NULL) {return NGX_ERROR;}/* 设置阶段回调函数 */*h = ngx_http_static_handler;return NGX_OK;
}

以上就是整个阶段处理的过程。理解之后发现并不难,而且可扩展性非常强,非常适合在不同阶段中挂载自定义的Nginx模块代码。

下一章,也是最后一章,我们讲解一下自定义模块的实现。

转载地址:

1. https://initphp.blog.csdn.net/article/details/72899546

Nginx源码分析 - HTTP模块篇 - HTTP模块的阶段处理PHASE handler(23)相关推荐

  1. nginx源码分析(2)——http模块的初始化过程

    前一篇文章介绍了nginx的启动初始化过程,包括了所有模块的初始化过程,比如http模块.事件模块等.这里再详细介绍一下http模块的启动过程,还记得在前一篇文章中提到过ngx_conf_parse函 ...

  2. Nginx 源码分析

    1.工程 ngx_conf_file.c ngx_connection.c ngx_cycle.c ngx_file.h ngx_module.c ngx_open_file_cache.h ngx_ ...

  3. Nginx源码分析:epoll事件处理模块概述

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 事件处理模块概述 Nginx的高效请求的处理依赖于事件管理机制,本次默认的场景是Linux操 ...

  4. Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 一

    搭建nginx服务器时,主要的配置文件 nginx.conf 是部署和维护服务器人员经常要使用到的文件, 里面进行了许多服务器参数的设置.那么nginx 以模块 module为骨架的设计下是如何运用模 ...

  5. nginx源码分析(5)——监听socket初始化

    在nginx源码分析(4)中,看到了nginx的事件模型,但其中没有介绍监听socket的初始化.而对于web server来说,需要通过监听socket来监听客户端的连接等.本篇将会具体介绍这方面的 ...

  6. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  7. Nginx源码分析:惊群处理与负载均衡

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> Nginx的惊群处理与负载均衡概述 当Nginx工作在master/worker模式下时,就 ...

  8. Nginx源码分析:核心数据结构ngx_cycle_t与内存池概述

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 核心数据结构与内存池概述 在Nginx中的核心数据结构就是ngx_cycle_t结构,在初始 ...

  9. Nginx源码分析:master/worker工作流程概述

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> Nginx的master与worker工作模式 在生成环境中的Nginx启动模式基本都是以m ...

  10. Nginx源码分析:启动流程

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> nginx简介 Nginx的作为服务端软件,表现的主要特点是更快.高扩展.高可靠性.低内存消 ...

最新文章

  1. 当输入 xxxxHub 后,到网页显示,其间发生了什么?
  2. nlm算法matlab代码_遗传算法GA的MATLAB代码
  3. 使用Spring 3.2的DeferredResult进行长轮询
  4. 云服务器带宽如何计算,云服务器怎么选择带宽
  5. Qt文档阅读笔记-Qt工作笔记-QThread解析与实例(主线程发送信号给子线程)
  6. 数字信号处理——巴特沃斯滤波器设计
  7. cacti监控mysql
  8. DNS DDNS NBNS mDNS LLMNR LLDPDU SSDP协议
  9. (原创)安卓抓包方案分享
  10. 有哪些公共管理或行政管理学习帮助较大的外文期刊?
  11. Web服务器及性能优化
  12. 看两宋风云,搞清了四个之前对两宋历史认识错误的地方
  13. 上海地铁二号线和一号线的差距
  14. URL Schemes 的发展
  15. 最强AngularJS资源合集
  16. Python写入数据到txt文本中
  17. AbMole推荐:人源化单抗动物实验黄金指南 (上)
  18. Unity导表工具Luban插件的数据加载原理与优化
  19. linux usleep占用cpu,c-Cent OS 6.3上的usleep的CPU高使用率
  20. 获取Excel单元格存储日期格式数据

热门文章

  1. Linux 下面解压.tar.gz 和.gz文件解压的方式
  2. HTML5 — 知识总结篇《VIII》【媒体元素】
  3. Android SwipeRefreshLayout 实现下拉刷新1
  4. SELECT中的多表连接
  5. 从P1到P7——我在淘宝这7年 - 子柳撰写
  6. 删除windows目录下的$NTUnintall$文件夹DOS命令
  7. mysql创建用户navicat_14MYSQL创建用户和授权、15Navicat的使用、16-pymysql模块的使用、17-索引...
  8. C/C++ 基础算法1
  9. Docker详解(十六)——Docker私有化仓库创建
  10. NYOJ--1100--WAJUEJI which home strong!