Nginx:handler模块按处理阶段挂载原理

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

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

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

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

typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,   // 接收到完整的HTTP头部后处理的阶段

    NGX_HTTP_SERVER_REWRITE_PHASE,  // URI与location匹配前,修改URI的阶段,用于重定向

    NGX_HTTP_FIND_CONFIG_PHASE,     // 根据URI寻找匹配的location块配置项
    NGX_HTTP_REWRITE_PHASE,         // 上一阶段找到location块后再修改URI
    NGX_HTTP_POST_REWRITE_PHASE,    // 防止重写URL后导致的死循环

    NGX_HTTP_PREACCESS_PHASE,       // 下一阶段之前的准备

    NGX_HTTP_ACCESS_PHASE,          // 让HTTP模块判断是否允许这个请求进入Nginx服务器
    NGX_HTTP_POST_ACCESS_PHASE,     // 向用户发送拒绝服务的错误码,用来响应上一阶段的拒绝

    NGX_HTTP_TRY_FILES_PHASE,       // 为访问静态文件资源而设置
    NGX_HTTP_CONTENT_PHASE,         // 处理HTTP请求内容的阶段,大部分HTTP模块介入这个阶段

    NGX_HTTP_LOG_PHASE              // 处理完请求后的日志记录阶段
} ngx_http_phases;

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

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

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

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

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

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

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

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

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

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

其中ngx_http_phase_handler_t定义如下:

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

下面将用一个例子来说明

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

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

ngx_int_t ngx_http_core_generic_phase(ngx_http_request_t *r,ngx_http_phase_handler_t *ph)
{
    //调用这一阶段中个HTTP模块添加的handler处理方法
    ngx_int_t rc=ph->handler(r);
    //如果hanlder方法返回NGX_OK,将进入下一阶段处理
    if(rc==NGX_OK){
        r->phase_handler=ph->next;
        return NGX_AGAIN;
    }
    //如果handler方法返回NGX_DECLINED,那么将进入下一个处理方法,这个处理方法即可以属于当前阶段,也可能属于下一阶段
    if(rc==NGX_DECLINED){
        r->phase_handler++;
        return NGX_AGAIN;
    }
    //如果handler方法返回NGX_AGAIN或者NGX_DONE,那么当前请求将依然停留在这一处理阶段
    if(rc==NGX_AGAIN||rc==NGX_DONE){
        return NGX_OK;
    }
    //如果hanlder方法返回其他,则调用ngx_http_finalize_request结束请求
    ngx_http_finalize_request(r,rc);
    return NGX_OK;
}

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

时间: 2024-11-02 02:45:13

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

nginx -- handler模块(100%)

handler模块简介 相信大家在看了前一章的模块概述以后,都对nginx的模块有了一个基本的认识.基本上作为第三方开发者最可能开发的就是三种类型的模块,即handler,filter和load-balancer.Handler模块就是接受来自客户端的请求并产生输出的模块.有些地方说upstream模块实际上也是一种handler模块,只不过它产生的内容来自于从后端服务器获取的,而非在本机产生的. 在上一章提到,配置文件中使用location指令可以配置content handler模块,当Ng

nginx http模块开发入门

导语 本文对nginx http模块开发需要掌握的一些关键点进行了提炼,同时以开发一个简单的日志模块进行讲解,让nginx的初学者也能看完之后做到心里有谱.本文只是一个用作入门的概述. 目录 背景 主线 认识nginx http请求处理流程 日志模块开发准备 配置解析流程 挂载处理函数 获取日志数据 模块编译 完整源码 结尾 背景 网上已经有很多介绍nginx http模块开发入门的文章,但是大多以hello_word程序为例,简单讲解一下代码,看完之后可能只能够依葫芦画瓢,做不了其它事情,更不

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

一.进程.线程? 进程是具有一定独立功能的,在计算机中已经运行的程序的实体.在早期系统中(如linux 2.4以前),进程是基本运作单位,在支持线程的系统中(如windows,linux2.6)中,线程才是基本的运作单位,而进程只是线程的容器.程序 本身只是指令.数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例.若干进程有可能与同一个程序相关系,且每个进程皆可以同步(循 序)或异步(平行)的方式独立运行.现代计算机系统可在同一段时间内以进程的形式将多个程序加载到存储器中,并借

Nginx Http模块开发

关于Nginx Http模块开发的文章非常少,只有Emiler的那篇关于Http模块的文章,但是那篇文章里面,并没有说到事件型的模块如何进行开发.而且文章里面提到的内容实在是让人有点意犹未尽.因此,对于Http事件型模块的开发进行了一些总结,与大家分享.但是,无论如何,要进行Nginx模块开发,最好的方法还是找到相似性较大的模块的代码进行参考,多试多看. 通常,一个Http模块均是有以下的几个部分组成: 1.模块配置结构体:(configure structure) 负责存储配置项的内容,每一条

Nginx的模块开发指南

原文:http://www.evanmiller.org/nginx-modules-guide.html 译文:http://blog.csdn.net/tab_tab_tab/article/details/51407418 解蝙蝠侠的漫画人物有助于充分认识Nginx.Web服务器. 首先,蝙蝠侠快. Nginx也快. 然后,蝙蝠侠同犯罪做斗争,Nginx和浪费CPU周期和内存泄漏做斗争. 最后,蝙蝠侠在压力下进行 工作.Nginx就其本身而言,擅长重的服务器负载下运行. 但是,蝙蝠侠将在没

Nginx服务模块详解

Nginx 工作原理 Nginx 由内核和模块组成 Nginx 本身做的工作实际很少,当它接到一个 HTTP 请求时, 它仅仅是通过查找配置文件将此次请求映射到一个 location block,而此 location 中所配 置的各个指令则会启动不同的模块去完成工作,因此模块可以看做 Nginx 真正的劳动工作者. 通常一个 location 中的指令会涉及一个 handler 模块和多个 filter 模块(当然,多个 location 可以复用同一个模块).handler 模块负责处理请求

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

nginx可以轻松实现根据不同的url 或者 get参数来转发到不同的服务器,然而当我们需要根据http包体来进行请求路由时,nginx默认的配置规则就捉襟见肘了,但是没关系,nginx提供了强大的自定义模块功能,我们只要进行需要的扩展就行了. 我们来理一下思路,我们的需求是: nginx根据http包体的参数,来选择合适的路由 在这之前,我们先来考虑另一个问题: 在nginx默认配置的支持下,能否实现服务器间的跳转呢?即类似于状态机,从一个服务器执行OK后,跳转到另一台服务器,按照规则依次传递

Nginx 事件模块

概述 Nginx 是以事件的触发来驱动的,事件驱动模型主要包括事件收集.事件发送.事件处理(即事件管理)三部分.在Nginx 的工作进程中主要关注的事件是 IO 网络事件 和 定时器事件.在生成的 objs 目录文件中,其中ngx_modules.c 文件的内容是 Nginx 各种模块的执行顺序,我们可以从该文件的内容中看到事件模块的执行顺序为以下所示:注意:由于是在 Linux 系统下,所以支持具体的 epoll 事件模块,接下来的文章结构按照以下顺序来写. extern ngx_module

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

1.Nginx配置文件主要组成:main(全局配置)这部分的指令将影响其他所有部分.server(虚拟主机配置)这部分指令主要用于指定虚拟主机域名,IP和端口.upstream(主要为反向代理,负载均衡相关配置)这部分指令用于设置反向代理及后端服务 器的负载均衡.location(目录匹配配置)这部分指令用于匹配网页位置(例如,根目录"/","/images",等 等). location部分会继承server部分的指令,而server部分会继承main部分的指令.