nginx模块开发
nginx模块开发
By 薛长俊 2013-11
Nginx模块开发
模块化 daemon 编码规范
模块化
• 模块分类
handlers,处理http请求并构造输出 filters,处理handler产生的输出 load-balancers,当有多于一个的后端服务器时,选择一台将http请求发 送过去
模块化
daemon
• 编写Handler
Nginx允许handler一次产生一组输出,可以产生多次,Nginx将输出组织成一 个单链表结构,链表中的每个节点是一个chain_t。
daemon
• 组合Nginx Module
一个Nginx模块被定义为一个ngx_module_t结构,这个结构的字段很多,不 过开头和结尾若干字段一般可以通过Nginx内置的宏去填充,下面是我们 echo模块的模块主体定义:
模块化
• ngx_module_t,ngx_module_s
ngx_uint_t type; //用于区分core、event、http和mail。 ngx_int_t (*init_master)(ngx_log_t *log); //初始化master时执行 ngx_int_t (*init_module)(ngx_cycle_t *cycle); //初始化module时执行 ngx_int_t (*init_process)(ngx_cycle_t *cycle); //初始化process时执行 ngx_int_t (*init_thread)(ngx_cycle_t *cycle); //初始化thread时执行 void (*exit_thread)(ngx_cycle_t *cycle); //退出thread时执行 void (*exit_process)(ngx_cycle_t *cycle); //退出process时执行 void (*exit_master)(ngx_cycle_t *cycle); //退出master时执行 ....
daemon
• 定义指令
一个Nginx模块往往接收一至多个指令,echo模块接收一个指令“echo”。 指令数组的命名规则为ngx_http_[module-name]_commands,注意数组 最后一个元素要是ngx_null_command结束。
daemon
• 定义参数转化函数
这个函数除了调用ngx_conf_set_str_slot转化echo指令的参数外,还将修改 了核心模块配置(也就是这个location的配置),将其handler替换为我们编 写的handler:ngx_http_echo_handler。这样就屏蔽了此location的默认 handler,使用ngx_http_echo_handler产生HTTP响应。
}
模块化
• 上下文
typedef struct { ngx_int_t (*preconfiguration)(ngx_conf_t *cf); //读入配置文件前调用 ngx_int_t (*postconfiguration)(ngx_conf_t *cf); //读入配置文件后调用 void *(*create_main_conf)(ngx_conf_t *cf); //创建main配置时调用 char *(*init_main_conf)(ngx_conf_t *cf, void *conf); //初始化main配置时
模块化
• 函数执行时机
• 当服务读配置文件之前 • 读存在location和server或其他任何部分的每一个配置指令 • 当Nginx初始化全局部分的配置时 • 当Nginx初始化主机部分(比如主机/端口)的配置时 • 当Nginx将全局部分的配置与主机部分的配置合并的时候 • 当Nginx初始化位置部分配置的时候 • 当Nginx将其上层主机配置与位置部分配置合并的时候 • 当Nginx的主(master)进程开始的时候 • 当一个新的工作进程(worker)开始的时候 • 当一个工作进程退出的时候 • 当主进程退出的时候 • 处理请求
模块化
• 上下文
模块上下文是四个结构体定义的:ngx_core_module_t、ngx_event_module_t、 ngx_http_module_t、ngx_mail_module_t,分别对应于四类模块。 typedef struct { ngx_str_t name; void *(*create_conf)(ngx_cycle_t *cycle); //创建并初始化conf char *(*init_conf)(ngx_cycle_t *cycle, void *conf); //赋值给conf } ngx_core_module_t; typedef struct { ngx_str_t *name; void *(*create_conf)(ngx_cycle_t *cycle); char *(*init_conf)(ngx_cycle_t *cycle, void *conf); ngx_event_actions_t actions; //模块的操作handler, 如epoll的init、 add、del等 ngx_event_module_t;
首先我们需要一个结构用于存储从配置文件中读进来的相关指令参数,即模 块配置信息结构。根据Nginx模块开发规则,这个结构的命名规则为: ngx_http_[module-name]_[main|srv|loc]_conf_t 其中,main、srv和loc分别用于表示同一模块在三层block中的配置信息。 这里我们的echo模块只需要运行在loc层级下,需要存储一个字符串参数, 因此我们可以定义如下的模块配置:
daemon
• 定义模块Context
首先需要定义一个ngx_http_module_t类型的结构体变量,命名规则为: ngx_http_[module-name]_module_ctx 这个结构主要用于定义各个Hook函数。下面是echo模块的context结构:
其中create_loc_conf用于初始化一个配置结构体,如为配置结构体分配内存 等工作;merge_loc_conf用于将其父block的配置信息合并到此结构体中,也 就是实现配置的继承。这两个函数会被Nginx自动调用。 命名规则: ngx_http_[module-name]_[create|merge]_[main|srv|loc]_conf。
daemon
• 编写模块config文件
这个文件需要放在和模块源代码文件放在同一目录下。 文件内容如下:
我们的config文件:
daemon
• 编译安装
编译安装命令:
修改nginx配置并启动:
ngx_module_t *ngx_modules[] = { &ngx_core_module, &ngx_errlog_module, &ngx_conf_module, &ngx_events_module, …. }
模块化
• ngx_module_t,ngx_module_s
typedef struct ngx_module_s ngx_module_t; struct ngx_module_s { ngx_uint_t ctx_index; //分类的模块计数器,nginx模块分为四 种:core、event、http和mail,每个模块都会各自计数。
daemon
• 定义create、merge函数
daemon
• 编写Handler
handler可以说是模块中真正干活的代码,它主要有以下四项职责: 读入模块配置; 处理功能业务; 产生HTTP header; 产生HTTP body;
daemon
• 编写Handler
daemon
• 编写Handler
模块化
• ngx_command_t中type取值
NGX_HTTP_MAIN_CONF: 指令出现在全局配置部分是合法的 NGX_HTTP_SRV_CONF: 指令在主机配置部分出现是合法的 NGX_HTTP_LOC_CONF: 指令在位置配置部分出现是合法的 NGX_HTTP_UPS_CONF: 指令在上游服务器配置部分出现是合法的 NGX_CONF_NOARGS: 指令没有参数 NGX_CONF_TAKE1: 指令读入一个参数 NGX_CONF_TAKE2: 指令读入两个参数 ... 更多取值参照core/ngx_conf_file.h
模块化
• 函数执行时机
• 过滤回复的头部 • 过滤回复的主体 • 选择一台后端服务器 • 初始化到后端服务器的请求 • 重新初始化到后端的服务器的请求 • 处理来自后端服务器的回复 • 完成与后端服务器的交互
模块化
• 模块定义(objs/ngx_modules.c )
extern extern extern extern … ngx_module_t ngx_module_t ngx_module_t ngx_module_t ngx_core_module; ngx_errlog_module; ngx_conf_module; ngx_events_module;
调用
void *(*create_srv_conf)(ngx_conf_t *cf); //创建server配置时调用 char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); //与 main配置合并时调用 void *(*create_loc_conf)(ngx_conf_t *cf); //创建location时调用 char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); //与 server配置合并时调用 } ngx_http_module_t;