标签:div master and 问题 pre block strong 命名 存储位置
HTTP框架是Nginx基础框架的一部分,Nginx的其它底层框架如master-worker进程模型、event模块、mail 模块等。
HTTP框架代码主要有2个模块组成:ngx_http_module和ngx_http_core_module;
我们编写的HTTP模块需要注册到HTTP框架上,才能融入HTTP请求的处理流程中。
当在nginx.conf中存在一个http{...}的配置时,即启用了HTTP框架代码,在nginx配置解析时,就已经为框架建立好了各种数据结构(尤其是HTTP模块的挂载);
当nginx收到请求时,请求完全按照HTTP框架建立好的这种逻辑进行处理。
一、HTTP模块开发基础
开发一个HTTP模块,需要下面几个数据结构:
1. HTTP模块配置结构
用于存储从配置文件读进来的相关指令参数;
配置模块的context有三种,分别是main、server和location,它们分别位于于http{...}、server{...}和location{...}上下文中。
其名称约定如下:ngx_http_<module name>_(main|srv|loc)_conf_t
2.HTTP 模块配置指令
模块的指令是定义在一个叫做ngx_command_t的静态数组中的;
ngx_command_t数组以ngx_null_command为终结符。
struct ngx_command_t {
ngx_str_t name; // 指令名称
ngx_uint_t type; // 指令所在的context和包含的参数个数
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); // 解析配置,并将参数存入模块配置结构体中
ngx_uint_t conf; // 指令参数的存储位置
ngx_uint_t offset; // 指令参数的存储偏移量
void *post;
};
其中,
type 成员表明这个指令允许出现的context、参数个数:
* NGX_HTTP_MAIN_CONF: 指令出现在main配置部分是合法的
* NGX_HTTP_SRV_CONF: 指令在server配置部分出现是合法的 config
* NGX_HTTP_LOC_CONF: 指令在location配置部分出现是合法的
* NGX_HTTP_UPS_CONF: 指令在upstream配置部分出现是合法的
* NGX_CONF_NOARGS: 指令没有参数
* NGX_CONF_TAKE1: 指令读入1个参数
* NGX_CONF_TAKE7: 指令读入7个参数
* NGX_CONF_FLAG: 指令读入1个布尔型数据 ("on" or "off")
* NGX_CONF_1MORE: 指令至少读入1个参数
* NGX_CONF_2MORE: 指令至少读入2个参数
set 成员是一个函数指针,用于模块参数解析,可以将配置文件中的模块参数传递给模块;
该函数会在遇到指令时执行,函数有三个入参:
a. 指向结构体 ngx_conf_t 的指针, 这个结构体里包含需要传递给指令的参数
b. 指向结构体 ngx_command_t 的指针
c. 指向模块自定义配置结构体的指针
Nginx内部提供了多个函数用来保存特定类型的数据,这些函数包括:
* ngx_conf_set_flag_slot: 将 "on" or "off" 转换成 1 or 0
* ngx_conf_set_str_slot: 将字符串保存为 ngx_str_t
* ngx_conf_set_num_slot: 解析一个数字并保存为int
* ngx_conf_set_size_slot: 解析一个数据大小(如:"8k", "1m") 并保存为size_t
conf 成员告诉Nginx把数据存在模块的哪个context中
* NGX_HTTP_MAIN_CONF_OFFSET
* NGX_HTTP_SRV_CONF_OFFSET
* NGX_HTTP_LOC_CONF_OFFSET
offset 成员确定保存在结构体的哪个位置;
post 成员指向模块在读配置的时候需要的一些零碎变量,一般为NULL。
3. HTTP模块上下文结构
静态的ngx_http_module_t结构体,用来创建和合并三段context (main,server,location),
其命名方式一般是:ngx_http_<module name>_module_ctx,
typedef struct {
ngx_int_t (*preconfiguration)(ngx_conf_t *cf); // 在读入配置前调用
ngx_int_t (*postconfiguration)(ngx_conf_t *cf); // 在读入配置后调用,用于挂载handler
void *(*create_main_conf)(ngx_conf_t *cf); // 在创建main配置时调用(比如,用来分配空间和设置默认值)
char *(*init_main_conf)(ngx_conf_t *cf, void *conf); // 在初始化main配置时调用(比如,把原来的默认值用nginx.conf读到的值来覆盖)
void *(*create_srv_conf)(ngx_conf_t *cf); // 在创建server配置时调用
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); // 合并server和main配置时调用
void *(*create_loc_conf)(ngx_conf_t *cf); // 创建location配置时调用,用于为指令参数结构体分配内存和初始化
char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); // 合并location和server配置时调用
} ngx_http_module_t;
这些回调是在ngx_http_block()解析http{...}配置时完成的:
当遇到一个 http{...} 时,HTTP框架会调用所有HTTP模块可能实现的create_main_conf、create_srv_conf、create_loc_conf生成存储main级别配置参数结构体;
当遇到一个server{...}时,HTTP框架会调用所有HTTP模块可能实现的create_srv_conf、create_loc_conf生成存储server级别配置参数结构体;
当遇到一个location{...}时,HTTP框架会调用所有HTTP模块可能实现的create_loc_conf生成存储location级别配置参数结构体;
因此,我们开发的HTTP模块中create_loc_conf方法被调用的次数等于http{...}、server{...}、location{...}在nginx.conf出现的次数之和;
create_srv_conf方法被调用的次数等于server{...}、location{...}在nginx.conf出现的次数之和;
由于只有一个http{...},所以create_main_conf方法只会被调用一次;
HTTP创建了如此多的结构体来存放配置项,是为了解决同名配置项的合并问题。
4、HTTP模块定义
一个Nginx模块被定义为一个ngx_module_t 结构,
该结构体变量命名方式为ngx_http_<module-name>_module
它包含模块的内容和指令执行方式,同时还包含一些回调函数来处理线程/进程的创建和销毁;
模块定义在有的时候会被用作查找的关键字,来查找与特定模块相关联的数据。
struct ngx_module_s {
ngx_uint_t ctx_index; // 在所有的HTTP模块中的序列号
ngx_uint_t index; // 在所有模块中的序列号
ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t spare2;
ngx_uint_t spare3;
ngx_uint_t version;
void *ctx; // 模块上下文
ngx_command_t *commands; // 模块配置指令
ngx_uint_t type; // 模块类型,HTTP模块应为NGX_HTTP_MODULE
ngx_int_t (*init_master)(ngx_log_t *log);
ngx_int_t (*init_module)(ngx_cycle_t *cycle);
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);
void (*exit_process)(ngx_cycle_t *cycle);
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;
};
注意:在configure之后生成的文件 objs/ngx_modules.c 中包含了模块的编译顺序。
1、解析HTTP配置的流程
首先要理解 ngx_conf_parse() 的递归解析流程;
nginx在解析nginx.conf的时候,没读取一行配置项,就执行该配置项的解析回调(handler);
Nginx Http框架的理解
标签:div master and 问题 pre block strong 命名 存储位置
原文地址:http://www.cnblogs.com/zhaolizhe/p/6923469.html