关注校招、实习信息
Nginx 模块概述
Nginx 模块有三种角色:
- 处理请求并产生输出的 Handler 模块;
- 处理由 Handler 产生的输出的 Filter(滤波器)模块;
- 当出现多个后台服务器时,Load-balancer (负载均衡器)模块负责选择其中一个后台服务器发送请求;
通常,服务器启动时,任何
Handler 模块都有可能去处理配置文件中的
location 定义。若出现多个
Handler 模块被配置成需要处理某一特定的
location 时,最终只有其中一个
Handler 模块是成功的。
Handler 模块有三种返回方式:
- 接收请求,并成功返回;
- 接收请求,但是出错返回;
- 拒绝请求,使默认的 Handler 模块处理该请求;
若
Handler 模块没有产生错误返回时,则会调用
Filter 模块。每个
location 配置里都可以添加多个
Filter 模块 ,因此响应可以被压缩和分块。
Filter 模块之间的处理顺序是在编译时就已经确定的。
Filter 模块采用“
CHAIN OF RESPONSIBILITY”链式的设计模式。当有请求到达时,请求依次经过这条链上的全部
Filter 模块,一个
Filter 被调用并处理,接下来调用下一个
Filter,直到最后一个
Filter 被调用完成,
Nginx 才真正完成响应流程。
总结如下,典型的处理形式如下:
Client sends HTTP request → Nginx chooses the appropriate handler based on the location config →
(if applicable) load-balancer picks a backend server →
Handler does its thing and passes each output buffer to the first filter →
First filter passes the output to the second filter → second to third → third to fourth → etc.
→ Final response sent to client
Nginx 模块的结构
模块的配置结构
模块最多可以定义三个配置结构:
main、
server、
location。绝大多数模块仅需要一个
location 配置。名称约定如下以
ngx_http_<module name>_(main|srv|loc)_conf_t为例的
dav module:
typedef struct {
ngx_uint_t methods;
ngx_flag_t create_full_put_path;
ngx_uint_t access;
} ngx_http_dav_loc_conf_t;
Nginx 模块的数据结构如下定义:
/* Nginx 模块的数据结构 */
#define NGX_MODULE_V1 0, 0, 0, 0, 0, 0, 1
#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0
struct ngx_module_s {
/* 模块类别由type成员决定,ctx_index表示当前模块在type类模块中的序号 */
ngx_uint_t ctx_index;
/* index 区别与ctx_index,index表示当前模块在所有模块中的序号 */
ngx_uint_t index;
/* spare 序列保留变量,暂时不被使用 */
ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t spare2;
ngx_uint_t spare3;
/* 当前模块的版本 */
ngx_uint_t version;
/* ctx指向特定类型模块的公共接口,例如在HTTP模块中,ctx指向ngx_http_module_t结构体 */
void *ctx;
/* 处理nginx.conf中的配置项 */
ngx_command_t *commands;
/* type表示当前模块的类型 */
ngx_uint_t type;
/* 下面的7个函数指针是在Nginx启动或停止时,分别调用的7中方法 */
/* 在master进程中回调init_master */
ngx_int_t (*init_master)(ngx_log_t *log);
/* 初始化所有模块时回调init_module */
ngx_int_t (*init_module)(ngx_cycle_t *cycle);
/* 在worker进程提供正常服务之前回调init_process初始化进程 */
ngx_int_t (*init_process)(ngx_cycle_t *cycle);
/* 初始化多线程 */
ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
/* 退出多线程 */
void (*exit_thread)(ngx_cycle_t *cycle);
/* 在worker进程停止服务之前回调exit_process */
void (*exit_process)(ngx_cycle_t *cycle);
/* 在master进程退出之前回调exit_master */
void (*exit_master)(ngx_cycle_t *cycle);
/* 保留字段,未被使用 */
uintptr_t spare_hook0;
uintptr_t spare_hook1;
uintptr_t spare_hook2;
uintptr_t spare_hook3;
uintptr_t spare_hook4;
uintptr_t spare_hook5;
uintptr_t spare_hook6;
uintptr_t spare_hook7;
};
在该数据结构中,其中最重要的是两个成员
ctx和
commands,这里两个成员会在分别在下面的模块配置指令和模块上下文中讲解;若是
HTTP 模块时,
type 字段必须定义为
NGX_HTTP_MODULE;
模块配置指令
模块指令存储在一个
ngx_command_t 类型的静态数组结构中,例如:
static ngx_command_t ngx_http_circle_gif_commands[] = {
{ ngx_string("circle_gif"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_circle_gif,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("circle_gif_min_radius"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_circle_gif_loc_conf_t, min_radius),
NULL },
...
ngx_null_command
};
ngx_command_t 类型定义在
core/ngx_conf_file.h:
struct ngx_command_s {
/* 配置项名称 */
ngx_str_t name;
/* 配置项类型,type将指定配置项可以出现的位置以及携带参数的个数 */
ngx_uint_t type;
/* 处理配置项的参数 */
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
/* 在配置文件中的偏移量,conf与offset配合使用 */
ngx_uint_t conf;
ngx_uint_t offset;
/* 配置项读取后的处理方法,必须指向ngx_conf_post_t 结构 */
void *post;
};
name :配置指令的名称;
type :该配置的类型,指定配置项的出现位置以及可携带参数的个数,下面规定只是其中一部分,更多信息可查看文件 core/ngx_conf_file.h:
NGX_HTTP_MAIN_CONF: directive is valid in the main config
NGX_HTTP_SRV_CONF: directive is valid in the server (host) config
NGX_HTTP_LOC_CONF: directive is valid in a location config
NGX_HTTP_UPS_CONF: directive is valid in an upstream config
NGX_CONF_NOARGS: directive can take 0 arguments
NGX_CONF_TAKE1: directive can take exactly 1 argument
NGX_CONF_TAKE2: directive can take exactly 2 arguments
…
NGX_CONF_TAKE7: directive can take exactly 7 arguments
NGX_CONF_FLAG: directive takes a boolean ("on" or "off")
NGX_CONF_1MORE: directive must be passed at least one argument
NGX_CONF_2MORE: directive must be passed at least two arguments
set :这是一个函数指针,当
Nginx 在解析配置时,若遇到该配置指令,将会把读取到的值传递给这个函数进行分解处理。因为具体每个配置指令的值如何处理,只有定义这个配置指令的人是最清楚的。来看一下这个函数指针要求的函数原型。
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
该函数处理成功时,返回
NGX_OK,否则返回
NGX_CONF_ERROR 或者是一个自定义的错误信息的字符串。该函数传入三个类型的参数:
- cf :指向ngx_conf_t 结构的指针,该结构包括从配置指令传递的参数;
- cmd:指向当前ngx_command_t 结构;
- conf:指向模块配置结构;
为了方便实现对配置指令参数的读取,
Nginx 已经默认提供了对一些标准类型的参数进行读取的函数,可以直接赋值给
set 字段使用。下面是一部分已经实现的
set 类型函数,更多可参考文件
core/ngx_conf_file.h:
- ngx_conf_set_flag_slot : 把 "