《深入理解Nginx:模块开发与架构解析》一3.5 定义自己的HTTP模块

本文涉及的产品
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 本节书摘来自华章出版社《深入理解Nginx:模块开发与架构解析》一书中的第3章,第3.5节,作者 陶辉,更多章节内容可以访问云栖社区“华章计算机”公众号查看

3.5 定义自己的HTTP模块

上文中我们了解了定义HTTP模块时需要定义哪些成员以及实现哪些方法,但在定义HTTP模块前,首先需要确定自定义的模块应当在什么样的场景下开始处理用户请求,也就是说,先要弄清楚我们的模块是如何介入到Nginx处理用户请求的流程中的。从2.4节中的HTTP配置项意义可知,一个HTTP请求会被许多个配置项控制,实际上这是因为一个HTTP请求可以被许多个HTTP模块同时处理。这样一来,肯定会有一个先后问题,也就是说,谁先处理请求谁的“权力”就更大。例如,ngx_http_access_module模块的deny选项一旦得到满足后,Nginx就会决定拒绝来自某个IP的请求,后面的诸如root这种访问静态文件的处理方式是得不到执行的。另外,由于同一个配置项可以从属于许多个server、location配置块,那么这个配置项将会针对不同的请求起作用。因此,现在面临的问题是,我们希望自己的模块在哪个时刻开始处理请求?是希望自己的模块对到达Nginx的所有请求都起作用,还是希望只对某一类请求(如URI匹配了location后表达式的请求)起作用?
Nginx的HTTP框架定义了非常多的用法,我们有很大的自由来定义自己的模块如何介入HTTP请求的处理,但本章只想说明最简单、最常见的HTTP模块应当如何编写,因此,我们这样定义第一个HTTP模块介入Nginx的方式:
1)不希望模块对所有的HTTP请求起作用。
2)在nginx.conf文件中的http{}、server{}或者location{}块内定义mytest配置项,如果一个用户请求通过主机域名、URI等匹配上了相应的配置块,而这个配置块下又具有mytest配置项,那么希望mytest模块开始处理请求。
在这种介入方式下,模块处理请求的顺序是固定的,即必须在HTTP框架定义的NGX_HTTP_CONTENT_PHASE阶段开始处理请求,具体内容下文详述。
下面开始按照这种方式定义mytest模块。首先,定义mytest配置项的处理。从上文中关于ngx_command_t结构的说明来看,只需要定义一个ngx_command_t数组,并设置在出现mytest配置后的解析方法由ngx_http_mytest“担当”,如下所示:

static ngx_command_t  ngx_http_mytest_commands[] = {

    { ngx_string("mytest"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_NOARGS,
      ngx_http_mytest,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },

      ngx_null_command
};

其中,ngx_http_mytest是ngx_command_t结构体中的set成员(完整定义为char (set)(ngx_conf_t cf, ngx_command_t cmd, void *conf);),当在某个配置块中出现mytest配置项时,Nginx将会调用ngx_http_mytest方法。下面看一下如何实现ngx_http_mytest方法。

static char *
ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_loc_conf_t  *clcf;

/首先找到mytest配置项所属的配置块,clcf看上去像是location块内的数据结构,其实不然,它可以是main、srv或者loc级别配置项,也就是说,在每个http{}和server{}内也都有一个ngx_http_core_loc_conf_t结构体/

clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

/HTTP框架在处理用户请求进行到NGX_HTTP_CONTENT_PHASE阶段时,如果请求的主机域名、URI与mytest配置项所在的配置块相匹配,就将调用我们实现的ngx_http_mytest_handler方法处理这个请求/

clcf->handler = ngx_http_mytest_handler;

    return NGX_CONF_OK;
}

当Nginx接收完HTTP请求的头部信息时,就会调用HTTP框架处理请求,另外在11.6节描述的NGX_HTTP_CONTENT_PHASE阶段将有可能调用mytest模块处理请求。在ngx_http_mytest方法中,我们定义了请求的处理方法为ngx_http_mytest_handler,举个例子来说,如果用户的请求URI是/test/example,而在配置文件中有这样的location块:

Location /test {
    mytest;
}

那么,HTTP框架在NGX_HTTP_CONTENT_PHASE阶段就会调用到我们实现的ngx_http_mytest_handler方法来处理这个用户请求。事实上,HTTP框架共定义了11个阶段(第三方HTTP模块只能介入其中的7个阶段处理请求,详见10.6节),本章只关注NGX_HTTP_CONTENT_PHASE处理阶段,多数HTTP模块都在此阶段实现相关功能。下面简单说明一下这11个阶段。

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

/在还没有查询到URI匹配的location前,这时rewrite重写URL也作为一个独立的HTTP阶段/

NGX_HTTP_SERVER_REWRITE_PHASE,

/根据URI寻找匹配的location,这个阶段通常由ngx_http_core_module模块实现,不建议其他HTTP模块重新定义这一阶段的行为/

NGX_HTTP_FIND_CONFIG_PHASE,

/在NGX_HTTP_FIND_CONFIG_PHASE阶段之后重写URL的意义与NGX_HTTP_SERVER_REWRITE_PHASE阶段显然是不同的,因为这两者会导致查找到不同的location块(location是与URI进行匹配的)/

NGX_HTTP_REWRITE_PHASE,

/这一阶段是用于在rewrite重写URL后重新跳到NGX_HTTP_FIND_CONFIG_PHASE阶段,找到与新的URI匹配的location。所以,这一阶段是无法由第三方HTTP模块处理的,而仅由ngx_http_core_module模块使用/

NGX_HTTP_POST_REWRITE_PHASE,

  //处理NGX_HTTP_ACCESS_PHASE阶段前,HTTP模块可以介入的处理阶段
  NGX_HTTP_PREACCESS_PHASE,

/*这个阶段用于让HTTP模块判断是否允许这个请求访问Nginx服务器

NGX_HTTP_ACCESS_PHASE,

/当NGX_HTTP_ACCESS_PHASE阶段中HTTP模块的handler处理方法返回不允许访问的错误码时(实际是NGX_HTTP_FORBIDDEN或者NGX_HTTP_UNAUTHORIZED),这个阶段将负责构造拒绝服务的用户响应。所以,这个阶段实际上用于给NGX_HTTP_ACCESS_PHASE阶段收尾/

NGX_HTTP_POST_ACCESS_PHASE,

/这个阶段完全是为了try_files配置项而设立的。当HTTP请求访问静态文件资源时,try_files配置项可以使这个请求顺序地访问多个静态文件资源,如果某一次访问失败,则继续访问try_files中指定的下一个静态资源。另外,这个功能完全是在NGX_HTTP_TRY_FILES_PHASE阶段中实现的/

NGX_HTTP_TRY_FILES_PHASE,
//用于处理HTTP请求内容的阶段,这是大部分HTTP模块最喜欢介入的阶段
  NGX_HTTP_CONTENT_PHASE,

/处理完请求后记录日志的阶段。例如,ngx_http_log_module模块就在这个阶段中加入了一个handler处理方法,使得每个HTTP请求处理完毕后会记录access_log日志/

NGX_HTTP_LOG_PHASE
} ngx_http_phases;

当然,用户可以在以上11个阶段中任意选择一个阶段让mytest模块介入,但这需要学习完第10章、第11章的内容,完全熟悉了HTTP框架的处理流程后才可以做到。
暂且不管如何实现处理请求的ngx_http_mytest_handler方法,如果没有什么工作是必须在HTTP框架初始化时完成的,那就不必实现ngx_http_module_t的8个回调方法,可以像下面这样定义ngx_http_module_t接口。

static ngx_http_module_t  ngx_http_mytest_module_ctx = {
    NULL,                        /* preconfiguration */
    NULL,                      /* postconfiguration */

    NULL,                         /* create main configuration */
    NULL,                         /* init main configuration */

    NULL,                        /* create server configuration */
    NULL,                         /* merge server configuration */

    NULL,                   /* create location configuration */
    NULL                     /* merge location configuration */
};

最后,定义mytest模块:

ngx_module_t  ngx_http_mytest_module = {
    NGX_MODULE_V1,
    &ngx_http_mytest_module_ctx,           /* module context */
    ngx_http_mytest_commands,              /* module directives */
    NGX_HTTP_MODULE,                       /* module type */
    NULL,                                  /* init master */
    NULL,                                  /* init module */
    NULL,                                  /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    NULL,                                  /* exit process */
    NULL,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};

这样,mytest模块在编译时将会被加入到ngx_modules全局数组中。Nginx在启动时,会调用所有模块的初始化回调方法,当然,这个例子中我们没有实现它们(也没有实现HTTP框架初始化时会调用的ngx_http_module_t中的8个方法)。

相关文章
|
2月前
|
缓存 JavaScript 安全
深度解析Nginx正向代理的原理与实现
深度解析Nginx正向代理的原理与实现
|
11天前
|
缓存 负载均衡 应用服务中间件
深入解析Nginx配置文件
Nginx是一个高性能HTTP服务器和反向代理,其配置文件`nginx.conf`包含全局、事件、HTTP、Server和Location块。全局块设置如用户和工作进程数,事件块设定连接数,HTTP块涉及MIME类型、日志和包含其他配置。Server块定义虚拟主机,Location块处理URI匹配。Nginx常用于反向代理和负载均衡,如`proxy_pass`指令转发请求至后端服务器组。理解这些配置有助于服务器优化和测试。
17 0
|
2月前
|
缓存 自然语言处理 前端开发
第一章 引言-HTTP协议基础概念和前后端分离架构请求交互概述
第一章 引言-HTTP协议基础概念和前后端分离架构请求交互概述
|
6天前
|
网络协议 PHP
Swoole 源码分析之 Http Server 模块
想要了解到 `Http Server` 的全貌,其实只要把那张整体的实现图看懂就足以了。但是,如果想要有足够的深度,那么就还需要深入 `Swoole` 的源代码中,就着源码自行分析一遍。同时,也希望这一次的分析,能够给大家带来对 `Swoole` 更多的一些了解。并不要求要深刻的掌握,因为,很多的事情都不可能一蹴而就。从自己的实力出发,勿忘初心。
15 0
Swoole 源码分析之 Http Server 模块
|
2月前
|
JavaScript 前端开发
基于 Node.js 环境,使用内置 http 模块,创建 Web 服务程序
基于 Node.js 环境,使用内置 http 模块,创建 Web 服务程序
|
13天前
|
JSON JavaScript 中间件
【Node.js】从基础到精通(三)—— HTTP 模块探索
【Node.js】从基础到精通(三)—— HTTP 模块探索
13 0
|
2月前
|
XML 数据格式
XML Schema 复杂元素类型详解:定义及示例解析
在XML Schema(XSD)中,复杂元素包含其他元素和/或属性,分为4类:空元素、仅含元素、仅含文本和既含元素也含文本。定义复杂元素可通过直接声明或引用预定义的复杂类型。复杂空元素仅含属性,而仅含元素的类型则只包含其他子元素。XSD提供了`<xs:sequence>`、`<xs:all>`、`<xs:choice>`等指示器来规定元素顺序和出现次数,以及`<xs:attributeGroup>`和`<xs:group>`来组织元素和属性。
191 7
|
2月前
|
运维 网络安全 Python
使用Python http.server模块共享文件
今天给大家介绍一下Python标准库中的http.server模块。这个模块提供了一种简单的方式来快速启动一个HTTP服务器,非常适合临时共享文件、测试、教学等轻量级场景。
|
2月前
|
安全 数据安全/隐私保护
企业邮箱解析:定义、特点全揭秘,通信安全护航
商务邮箱是专为企业的邮件服务系统,强调专业形象、高效沟通和信息安全。它提供邮件管理、会议安排等功能,增强品牌形象和内部效率。重要的是选择稳定且安全的服务商。商务邮箱使用企业域名,展示专业性并提升品牌识别度,包含群发管理、邮件追踪等高级功能。市场有多种服务商,如Zoho Mail和G Suite,选择时需考虑稳定性、安全性等因素。商务邮箱对提升企业形象、加强内部管理、保障信息安全、支持移动办公及客户服务起关键作用。
27 1
|
2月前
|
JSON 前端开发 搜索推荐
BoostCompass( http_server 模块 | 项目前端代码 )
BoostCompass( http_server 模块 | 项目前端代码 )
38 4

推荐镜像

更多