3.2 准备工作

Nginx模块需要使用C(或者C++)语言编写代码来实现,每个模块都要有自己的名字。按照Nginx约定俗成的命名规则,我们把第一个HTTP模块命名为ngx_http_mytest_module。由于第一个模块非常简单,一个C源文件就可以完成,所以这里按照官方惯例,将唯一的源代码文件命名为ngx_http_mytest_module.c。

实际上,我们还需要定义一个名称,以便在编译前的configure命令执行时显示是否执行成功(即configure脚本执行时的ngx_addon_name变量)。为方便理解,仍然使用同一个模块名来表示,如ngx_http_mytest_module。

为了让HTTP模块正常工作,首先需要把它编译进Nginx(3.3节会探讨编译新增模块的两种方式)。其次需要设定模块如何在运行中生效,比如在图3-1描述的典型方式中,配置文件中的location块决定了匹配某种URI的请求将会由相应的HTTP模块处理,因此,运行时HTTP框架会在接收完毕HTTP请求的头部后,将请求的URI与配置文件中的所有location进行匹配(事实上会优先匹配虚拟主机,第11章会详细说明该流程),匹配后再根据location{}内的配置项选择HTTP模块来调用。这是一种最典型的HTTP模块调用方式。3.4节将解释HTTP模块定义嵌入方式时用到的数据结构,3.5节将定义我们的第一个HTTP模块,3.6节中介绍如何使用上述模块调用方式来处理请求。

既然有典型的调用方式,自然也有非典型的调用方式,比如ngx_http_access_module模块,它是根据IP地址决定某个客户端是否可以访问服务的,因此,这个模块需要在NGX_HTTP_ACCESS_PHASE阶段(在第10章中会详述HTTP框架定义的11个阶段)生效,它会比本章介绍的mytest模块更早地介入请求的处理中,同时它的流程与图3-1中的不同,它可以对所有请求产生作用。也就是说,任何HTTP请求都会调用ngx_http_access_module模块处理,只是该模块会根据它感兴趣的配置项及所在的配置块来决定行为方式,这与mytest模块不同,在mytest模块中,只有在配置了location/uri{mytest;}后,HTTP框架才会在某个请求匹配了/uri后调用它处理请求。如果某个匹配了URI请求的location中没有配置mytest配置项,mytest模块依然是不会被调用的。

为了做到跨平台,Nginx定义、封装了一些基本的数据结构。由于Nginx对内存分配比较“吝啬”(只有保证低内存消耗,才可能实现十万甚至百万级别的同时并发连接数),所以这些Nginx数据结构天生都是尽可能少占用内存。下面介绍本章中将要用到的Nginx定义的几个基本数据结构和方法,在第7章还会介绍一些复杂的容器,读者可以从中体会到如何才能有效地利用内存。

3.2.1 整型的封装

Nginx使用ngx_int_t封装有符号整型,使用ngx_uint_t封装无符号整型。Nginx各模块的变量定义都是如此使用的,建议读者沿用Nginx的习惯,以此替代int和unsinged int。

在Linux平台下,Nginx对ngx_int_t和ngx_uint_t的定义如下:


typedef intptr_t

ngx_int_t;

typedef uintptr_t

ngx_uint_t;