参考资料<深入理解Nginx>(陶辉)

在Nginx中,handler模块真正的处理函数通过两种方式挂载到处理过程中,一种方式就是按处理阶段挂载;另外一种挂载方式就是按需挂载。

本次我们将讨论按处理阶段挂载的方法和原理。

Nginx把HTTP请求的处理过程分为11个阶段:

  1. typedef enum {
  2. NGX_HTTP_POST_READ_PHASE = , // 接收到完整的HTTP头部后处理的阶段
  3.  
  4. NGX_HTTP_SERVER_REWRITE_PHASE, // URI与location匹配前,修改URI的阶段,用于重定向
  5.  
  6. NGX_HTTP_FIND_CONFIG_PHASE, // 根据URI寻找匹配的location块配置项
  7. NGX_HTTP_REWRITE_PHASE, // 上一阶段找到location块后再修改URI
  8. NGX_HTTP_POST_REWRITE_PHASE, // 防止重写URL后导致的死循环
  9.  
  10. NGX_HTTP_PREACCESS_PHASE, // 下一阶段之前的准备
  11.  
  12. NGX_HTTP_ACCESS_PHASE, // 让HTTP模块判断是否允许这个请求进入Nginx服务器
  13. NGX_HTTP_POST_ACCESS_PHASE, // 向用户发送拒绝服务的错误码,用来响应上一阶段的拒绝
  14.  
  15. NGX_HTTP_TRY_FILES_PHASE, // 为访问静态文件资源而设置
  16. NGX_HTTP_CONTENT_PHASE, // 处理HTTP请求内容的阶段,大部分HTTP模块介入这个阶段
  17.  
  18. NGX_HTTP_LOG_PHASE // 处理完请求后的日志记录阶段
  19. } ngx_http_phases;

如果希望某个ngx_http_handler_pt处理方法应用于所有的用户请求,应该使用按处理阶段挂载。

挂载的时候应该实现该HTTP模块的postconfiguration方法,挂载代码如下:

  1. static ngx_int_t ngx_http_mytest_init(ngx_conf_t *cf)
  2. {
  3. //获取到全局的ngx_http_core_main_conf_t结构体
  4. ngx_http_core_main_conf_t *cmcf=ngx_http_conf_get_module_main_conf(cf,ngx_http_core_module);
  5. /*
    phases数组有11个成员,代表上面所说的11个阶段,取出需要挂载的某个阶段(NGX_HTTP_POST_READ_PHASE)的handlers动态数组,
    这样该模块就介入HTTP请求的(NGX_HTTP_POST_READ_PHASE)处理阶段了
    */
  6. h=ngx_array_push(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers);
  7. if(h==NULL){
  8. return NGX_ERROR;
  9. }
  10. *h=ngx_http_mytest_handler;
  11. }

下面分析一下该方法涉及到的数据结构,首先是全局的ngx_http_core_main_conf结构体:

  1. typedef struct {
  2. //该结构包含一个handler处理方法的数组,是HTTP请求处理顺序的关键
  3. ngx_http_phase_engine_t phase_engine;
  4. //用于在HTTP框架初始化时添加HTTP处理方法
  5. ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE+];
  6. ...
  7. } ngx_http_core_main_conf_t;

其中phases是一个数组,该数组元素的定义如下

  1. typedef struct {
  2. //该动态数组保存着每一个HTTP模块初始化时添加到当前阶段的处理方法
    ngx_array_t handlers;
  3. } ngx_http_phase_t;

因此,操作phases中的handlers成员,HTTP框架就会自动的向相应的处理阶段添加处理方法。

事实上,HTTP框架将使用phases数组来构建phase_engine成员。ngx_http_phase_engine_t结构如下:

  1. typedef struct {
  2. //handlers是一个数组的首地址,它表示一个请求可能经历的所有处理方法(可以说,每个方法对应一个序号,保证了HTTP处理的顺序执行)
  3. ngx_http_phase_handler_t *handlers;
  4. ...
  5. } ngx_http_phase_engine_t;

其中ngx_http_phase_handler_t定义如下:

  1. typedef struct ngx_http_parse_handler_s ngx_http_parse_handler_t;
    typedef ngx_int_t (*ngx_http_pharse_handler_pt) (ngx_http_request_t *r,ngx_http_phase_handler_t *ph);
    typedef ngx_int_t (*ngx_http_handler_pt) (ngx_http_request_t *r);
  2. //该结构体只代表处理阶段中的一个处理方法
  3. struct ngx_http_phase_handler_s {
  4. //在处理某一个HTTP阶段时,HTTP框架将调用checker方法来处理请求,只有checker方法才会调用handler方法(checker方法都是由框架中ngx_http_core_module模块实现的)
  5. ngx_http_phase_handler_pt checker;
  6. //第三方模块通过定义handler方法才能介入一个HTTP处理阶段以处理请求(HTTP框架会帮我们设置该成员,在此之前我们要设置好一些初始化信息:如上面的parses.handlers动态数组)
  7. ngx_http_handler_pt handler;
  8. //将要执行的下一个HTTP处理阶段的序号,通常表示下一个处理阶段的第一个ngx_http_phase_handler_t处理方法
  9. ngx_uint_t next;
  10. }

下面将用一个例子来说明

当HTTP框架在建立的TCP连接上接收到客户发送的完整HTTP请求头部时,开始执行NGX_HTTP_POST_READ_PHASE阶段的checker方法

关键是判断handler的返回值来判断执行的顺序(前面ngx_http_phase_engine_t包含了全部的处理方法,每个方法对应一个序号,根据序号就可以判断下一步执行的是哪个处理方法)

  1. ngx_int_t ngx_http_core_generic_phase(ngx_http_request_t *r,ngx_http_phase_handler_t *ph)
  2. {
  3. //调用这一阶段中个HTTP模块添加的handler处理方法
  4. ngx_int_t rc=ph->handler(r);
  5. //如果hanlder方法返回NGX_OK,将进入下一阶段处理
  6. if(rc==NGX_OK){
  7. r->phase_handler=ph->next;
  8. return NGX_AGAIN;
  9. }
  10. //如果handler方法返回NGX_DECLINED,那么将进入下一个处理方法,这个处理方法即可以属于当前阶段,也可能属于下一阶段
  11. if(rc==NGX_DECLINED){
  12. r->phase_handler++;
  13. return NGX_AGAIN;
  14. }
  15. //如果handler方法返回NGX_AGAIN或者NGX_DONE,那么当前请求将依然停留在这一处理阶段
  16. if(rc==NGX_AGAIN||rc==NGX_DONE){
  17. return NGX_OK;
  18. }
  19. //如果hanlder方法返回其他,则调用ngx_http_finalize_request结束请求
  20. ngx_http_finalize_request(r,rc);
  21. return NGX_OK;
  22. }

在此阶段中ngx_http_handler_pt方法的返回值可以产生4中不同的影响

Nginx:handler模块按处理阶段挂载原理的更多相关文章

  1. nginx -- handler模块(100%)

    handler模块简介 相信大家在看了前一章的模块概述以后,都对nginx的模块有了一个基本的认识.基本上作为第三方开发者最可能开发的就是三种类型的模块,即handler,filter和load-ba ...

  2. nginx http模块开发入门

    导语 本文对nginx http模块开发需要掌握的一些关键点进行了提炼,同时以开发一个简单的日志模块进行讲解,让nginx的初学者也能看完之后做到心里有谱.本文只是一个用作入门的概述. 目录 背景 主 ...

  3. nginx upstream模块

    upstream模块 upstream模块 (100%) nginx模块一般被分成三大类:handler.filter和upstream.前面的章节中,读者已经了解了handler.filter. 利 ...

  4. Nginx为什么比Apache Httpd高效:原理篇

    一.进程.线程? 进程是具有一定独立功能的,在计算机中已经运行的程序的实体.在早期系统中(如linux 2.4以前),进程是基本运作单位,在支持线程的系统中(如windows,linux2.6)中,线 ...

  5. Nginx Http模块开发

    关于Nginx Http模块开发的文章非常少,只有Emiler的那篇关于Http模块的文章,但是那篇文章里面,并没有说到事件型的模块如何进行开发.而且文章里面提到的内容实在是让人有点意犹未尽.因此,对 ...

  6. Nginx限速模块初探

    Nginx限速模块分为哪几种?按请求速率限速的burst和nodelay参数是什么意思?漏桶算法和令牌桶算法究竟有什么不同?本文将带你一探究竟.我们会通过一些简单的示例展示Nginx限速模块是如何工作 ...

  7. Dockerfile多阶段构建原理和使用场景

    本文转载自Dockerfile多阶段构建原理和使用场景 导语 Docker 17.05版本以后,新增了Dockerfile多阶段构建.所谓多阶段构建,实际上是允许一个Dockerfile 中出现多个 ...

  8. nginx自定义模块编写-根据post参数路由到不同服务器

    nginx可以轻松实现根据不同的url 或者 get参数来转发到不同的服务器,然而当我们需要根据http包体来进行请求路由时,nginx默认的配置规则就捉襟见肘了,但是没关系,nginx提供了强大的自 ...

  9. Nginx学习笔记六Nginx的模块开发

    1.Nginx配置文件主要组成:main(全局配置)这部分的指令将影响其他所有部分.server(虚拟主机配置)这部分指令主要用于指定虚拟主机域名,IP和端口.upstream(主要为反向代理,负载均 ...

随机推荐

  1. windows实时监测热插拔设备的变化(转)

    原文转自 https://blog.csdn.net/windows_nt/article/details/13614849 序: 在21世纪,这个信息时代,热插拔设备是一个巨大的安全隐患.在这个篇文 ...

  2. 华为上机测试题(数字字符串转二进制-java)

    PS:此题满分,可参考 /*  * 题目:数字字符串转二进制 * 描述: 输入一串整数,将每个整数转换为二进制数,如果倒数第三个Bit是“0”,则输出“0”,如果是“1”,则输出“1”. 题目类别: ...

  3. Linux的日志错误级别

    讯息等级 系统将讯息分为七个主要的等级,依序是由不重要排列到重要讯息等级: info:仅是一些基本的讯息说明而已: notice:比 info 还需要被注意到的一些信息内容: warning 或 wa ...

  4. MPchartAnadroid的对比柱状图

    1.导入三方jar包(可参照) MPAndroidChart(GitHub上优秀得图表功能库) MPAndroidChart常见设置属性(一)——应用层 2.布局activity_main.xml(这 ...

  5. 【转】Talend作业设计模式和最佳实践-Part I

    原文地址:https://mp.weixin.qq.com/s?__biz=MzA3OTg1Mzk4Nw==&mid=2453261363&idx=2&sn=e0f426022 ...

  6. 如何让springboot中的某些html文件不经过thymeleaf模板解析?

    这个thymeleaf有时有用,有时用不着. 但默认设置,所有的html都会经过它解析. 我的作法,是新建public,在resource里,所有css,js所放里面.(当然,static下也是OK的 ...

  7. J.U.C并发框架源码阅读(十六)FutureTask

    基于版本jdk1.7.0_80 java.util.concurrent.FutureTask 代码如下 /* * ORACLE PROPRIETARY/CONFIDENTIAL. Use is su ...

  8. maven配置memcached.jar

    由于目前java memcached client没有官方的maven repository可供使用,因此使用时需要手动将其安装到本地repository. java memcached client ...

  9. 每天一个liunx命令2之rz和sz命令

    1安装命令工具包     yum install lrzsz   2sz命令发送文件到本地(send): sz filename 3rz命令本地上传文件到服务器(receive): rz 执行该命令后 ...

  10. SQL常用函数之五 str()

    原文:SQL常用函数之五 str() 使用str函数   :STR 函数由数字数据转换来的字符数据.   语法      STR    (    float_expression    [    ,  ...