请在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

接着上次的文章,今天研究《深入理解Nginx模块开发与架构解析》一书中给出的mytest的例子,发现和 /tengine.taobao.org/book/一书中的例子不甚相同,尤其是在handler函数的挂在方面。

函数的挂载分为两种方式:

一种方式就是按处理阶段挂载;另外一种挂载方式就是按需挂载。tengine.taobao.org 中使用的挂载方式是按处理阶段挂载,而深入理解一书中的挂载方式是按需求挂载。

首先看/tengine.taobao.org/book/中的例子:

由我之前 Nginx_handler模块发开(hello模块结构解析)一文,handler_init就是handler函数的挂载函数,该函数在上下文结构中的postconfiguration字段被调用,决定handler函数在哪里被挂载。

 1 static ngx_http_module_t ngx_http_hello_module_ctx = {
2 NULL, /* preconfiguration */
3 ngx_http_hello_init, /* postconfiguration */
4
5 NULL, /* create main configuration */
6 NULL, /* init main configuration */
7
8 NULL, /* create server configuration */
9 NULL, /* merge server configuration */
10
11 ngx_http_hello_create_loc_conf, /* create location configuration */
12 NUL
 1 static ngx_int_t
2 ngx_http_hello_init(ngx_conf_t *cf)
3 {
4 ngx_http_handler_pt *h;
5 ngx_http_core_main_conf_t *cmcf;
6
7 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); //取得core_module的cf
8
9 h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); // 挂载函数到对应处理阶段
10 if (h == NULL) {
11 return NGX_ERROR;
12 }
13
14 *h = ngx_http_hello_handler; //将函数指针指向handler函数
15
16 return NGX_OK;
17 }

使用这种方式挂载的handler也被称为 content phase handlers

而在《深入理解Nginx模块开发与架构解析》一书中给出的mytest的例子中,则是按需求挂载:

以这种方式挂载的handler也被称为 content handler

当一个请求进来以后,nginx从NGX_HTTP_POST_READ_PHASE阶段开始依次执行每个阶段中所有handler。执行到 NGX_HTTP_CONTENT_PHASE阶段的时候,如果这个location有一个对应的content handler模块,那么就去执行这个content handler模块真正的处理函数。否则继续依次执行NGX_HTTP_CONTENT_PHASE阶段中所有content phase handlers,直到某个函数处理返回NGX_OK或者NGX_ERROR。

换句话说,当某个location处理到NGX_HTTP_CONTENT_PHASE阶段时,如果有content handler模块,那么NGX_HTTP_CONTENT_PHASE挂载的所有content phase handlers都不会被执行了。

但是使用这个方法挂载上去的handler有一个特点是必须在NGX_HTTP_CONTENT_PHASE阶段才能执行到。如果你想自己的handler在更早的阶段执行,那就不要使用这种挂载方式。

那么在什么情况会使用这种方式来挂载呢?一般情况下,某个模块对某个location进行了处理以后,发现符合自己处理的逻辑,而且也没有必要再调用NGX_HTTP_CONTENT_PHASE阶段的其它handler进行处理的时候,就动态挂载上这个handler。

mytest这个例子在配置结构中,直接调用了content handler函数,名为ngx_http_mytest,该函数直接实现了真正的handler函数的挂载执行:

 1 static ngx_command_t ngx_http_mytest_commands[] = {
2 {
3 ngx_string("mytest"),
4 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_NOARGS,
5 ngx_http_mytest,
6 NGX_HTTP_LOC_CONF_OFFSET,
7 0,
8 NULL
9 },
10 ngx_null_command
11 };

content handler函数 ngx_http_mytest的定义如下:

 1 static char *
2 ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3 {
4 ngx_http_core_loc_conf_t *clcf;
5
6 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
7
8 clcf->handler = ngx_http_mytest_handler;
9
10 return NGX_CONF_OK;
11 }

定义十分简单,主要就是一个ngx_http_conf_get_module_loc_conf函数的调用,以及一个函数指针的赋值。函数指针的赋值实现了真正的handler函数的挂载。

那么,我们来看看被调用的ngx_http_conf_get_module_loc_con函数的定义:

#define ngx_http_conf_get_module_loc_conf(cf, module)                         \
((ngx_http_conf_ctx_t *) cf->ctx)->loc_conf[module.ctx_index]

只是一个宏定义,主要作用是将之前存储起来的conf内容调出,赋值给clcf。

联系方式:rwhsysu@163.com。

个人理解,欢迎指正。

Nginx入门之两种handler函数的挂载方式的更多相关文章

  1. js两种定义函数、继承方式及区别

    一:js两种定义函数的方式及区别 1:函数声明: function sayA() { alert("i am A"); } 2:函数表达式: var sayB = function ...

  2. javascript两种声明函数的方式的一次深入解析

    声明函数的方式 javascript有两种声明函数的方式,一个是函数表达式定义函数,也就是我们说的匿名函数方式,一个是函数语句定义函数,下面看代码: /*方式一*/ var FUNCTION_NAME ...

  3. 两种const函数

    有两种const函数,声明如下:1.const T func();2.T func() const;第一种表示返回的是const的类型,也即返回的值不能作为左值,楼主懂的.第二种表示该成员函数不能修改 ...

  4. KbmMW两种查询结果集通讯方式

    KbmMW本身可以用QueryService的方式进行远程数据查询,但是SmpileService同样具有很强的扩展性可以实现数据查询,下面展示两种基于SmpileService的远程数据查询方法,其 ...

  5. reportConfig.xml两种数据源连接的配置方式

     在reportConfig.xml配置文件中,我们提供了两种数据源连接的配置方式,分别如下: 1.jndi数据源配置(即:在dataSource中配置) 此配置适用于在j2ee的服务器中配置了j ...

  6. 流式思想概述和两种获取Stream流的方式

    流式思想概述 整体来看,流式思想类似于工厂车间的生产流水线 当需要对多个元素进行操作(特别是多步操作)的时候,考虑到性能及便利性,我们应该首先拼好一个模型步骤方案,然后再按照方法去执行他 这张图中展示 ...

  7. JS里面的两种运动函数

    最新学了一个新的运动函数,与最初学习的有所不同,第一个运动是根据运动速度完成运动 ,第二个则是根据运动的时间来完成运动,而且把之前的函数都进行了一些兼容处理,在这里列出了看一下: 第一种animate ...

  8. 两种open()函数

    C语言中文件操作函数中,open()有两种形式: 一种形式是有两个参数open2: 另一种形式是有三个参数open3: 共有的参数有两个,第一个是"被打开文件的路径",第二个是&q ...

  9. Qt插件开发入门(两种方法:High-Level API接口,Low-Level API接口)

    Qt中为我们提供了两种开发插件的方式.一种是使用High-Level API接口,一种是使用Low-Level API接口.所谓High-Level API 是指通过继承Qt为我们提供的特定的插件基类 ...

随机推荐

  1. PYTHON的CGIServer的进化

    按例程,一步一步理解如何从SOCKET,TCP,HTTP,CGIHTTP进化的. 最终,静态文件和脚本分享,且能处理FORM提交和展示. 下一步,到数据库??:) A,SOCKET #HTTPserv ...

  2. HDOJ多校联合第六场

    先一道一道题慢慢补上, 1009.题意,一棵N(N<=50000)个节点的树,每个节点上有一个字母值,给定一个串S0(|S0| <=30),q个询问,(q<=50000),每次询问经 ...

  3. bulkTransfer通讯必须注意的问题:bulk buffer size(16K)

    Android USB host与HID使用bulkTransfer通讯接收和发送的数据长度不会超过16384,这个问题困扰了我很长一段时间,终于发现问题所在,不是出在我的程序设计,也不是硬件的发送/ ...

  4. Qt 自定义model实现文件系统的文件名排序

    前段时间,需要做一个功能是要做文件系统的排序的功能.由于是自己写的model, 自己定义的数据结构.最初的想法只有一个自己去实现文件夹跟文件名的排序算法,不过感觉比较费时间.后来想到的是QFileSy ...

  5. c#使用XSLT将xml文档转换为html文档

    需要引用下面的命名空间: using System.Xml; using System.Xml.Xsl; 方法实现: public static string ConvertXML(XmlDocume ...

  6. 【HDOJ】1258 Sum It Up

    典型的深搜,剪枝的时候需要跳过曾经搜索过的相同的数目,既满足nums[i]=nums[i-1]&&visit[i-1]==0,visit[i-1]==0可以说明该点已经测试过. #in ...

  7. MVC——数据库增删改查(Razor)——Html语法

    一.显示界面 .Models(模板) private MyDBDataContext _context = new MyDBDataContext(); public List<Info> ...

  8. Luogu_1565_牛宫_(最大子矩阵)

    描述 http://www.luogu.org/problem/show?pid=1565 给出一个n*m的矩阵,求最大的且和值为正的子矩阵. 分析 很容易想到的是用前缀和维护,暴力枚举左上角和右下角 ...

  9. SCOI2007排列perm

    1072: [SCOI2007]排列perm Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 805  Solved: 497[Submit][Stat ...

  10. 关于ButterKnife 8.1.0使用遇到的问题

    ButterKnife注解方式 和eventbus 差不多 都很好用 @OnClick(R.id.button) void onButtonClick() { //TODO implement Toa ...