背景:
在开发功能灵活的Nginx模块时,需要从配置文件中获取特定的信息,不过,不需要再 编写一套读取配置的系统,Nginx已经为用户提供了强大的配置项解析机制,同时它还支持“- s reload”命令——在不重启服务的情况下可使配置生效
预读知识
例子:
http {
test_str main;
server {
listen 80;
test_str server80;
location url1 {
mytest;
test_str loc1;
}
location url2 {
mytest;
test_str loc2;
}
}
server
listen 8080;
test_str server8080;
location /url3 {
mytest;
test_str loc3;
}
}
}
总体解析:
1.test_str这个配置项在http块内出现的值为main,在监听80端口的 server块内test_str值为server80,该server块内有两个location由mytest模块处理的且每个location中又重新设置了test_str的值,分别为loc1和loc2
2.在这之后又定义 了监听8080端口的server块,并重定义test_str的值为server8080,这个server块内定义的一个 location也是由mytest模块处理的,而且这个location内再次重定义了test_str的值为loc3。
效果:
在这段很短的配置中,mytest模块将会处理两个监听端口上建立的TCP连接,以及3种 HTTP请求,请求的URL分别对应着/url1、/url2、/url3
一个问题:
假设mytest模块必须取出test_str配置 项的参数,可是在以上的例子中test_str出现了6个不同的参数值,分别为main、server80、 server8080、loc1、loc2、loc3,那么在mytest模块中我们取到的test_str值以哪一个为准呢?
关于ngx_command_t结构
struct ngx_command_s {
ngx_str_t name;
ngx_uint_t type;
char (set)(ngx_conf_t cf, ngx_command_t cmd, void conf);
ngx_uint_t conf;
ngx_uint_t offset;
void post;
};
使用http配置项
1 创建数据结构用于存储配置项对应的参数
结构解析
typedef struct {
ngx_str_t my_str;
ngx_int_t my_num;
ngx_flag_t my_flag;
size_t my_size;
ngx_array_t* my_str_array;
ngx_array_t* my_keyval;
off_t my_off;
ngx_msec_t my_msec;
time_t my_sec;
ngx_bufs_t my_bufs;
ngx_uint_t my_enum_seq;
ngx_uint_t my_bitmask;
ngx_uint_t my_access;
ngx_path_t* my_path;
} ngx_http_mytest_conf_t;
成员解析:参照:一文读懂14种预设方法解析配置项_编程界的谢菲尔德的博客-CSDN博客
第二个问题:
为什么要这么严格地用一个结构体来存储配置项的参数值,而不是随意地定义几个全局 变量来存储它们呢?
初始化ngx_http_mytest_conf_t利用ngx_module_t结构
//回顾
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);
char (*init_main_conf)(ngx_conf_t cf, void conf);
void (create_srv_conf)(ngx_conf_t cf);
char (*merge_srv_conf)(ngx_conf_t cf, void prev, void *conf);
void (create_loc_conf)(ngx_conf_t cf);
char (*merge_loc_conf)(ngx_conf_t cf, void prev, void *conf);
} ngx_http_module_t;
解析:create_main_conf、create_srv_conf、create_loc_conf这3个回调方法负责把我们分 配的用于保存配置项的结构体传递给HTTP框架
问题三
为什么不是定义1个而是定义 3个回调方法
方法
普通的HTTP模块往往只实现create_loc_conf回调方法,因为它们只关注匹配某种URL的 请求。我们的mytest例子也是这样实现的,这里实现create_loc_conf的是 ngx_http_mytest_create_loc_conf方法
static void* ngx_http_conf_get_module_loc_conf(ngx_con_t cf)
{
ngx_http_mytest_con_f mycf;
mycf=(ngx_http_mytest_con_f*)ngx_pcalloccf->pool, sizeof(ngx_http_mytest_conf_t));
if(mycf==NULL)
{
return NULL;
}
mycf->my_flag = NGX_CONF_UNSET;
mycf->my_num = NGX_CONF_UNSET;
mycf->my_str_array = NGX_CONF_UNSET_PTR;
mycf->my_keyval = NULL;
mycf->my_off = NGX_CONF_UNSET;
mycf->my_msec = NGX_CONF_UNSET_MSEC;
mycf->my_sec = NGX_CONF_UNSET;
mycf->my_size = NGX_CONF_UNSET_SIZE;
return mycf;
}
问题解析
问题一:
事实上,Nginx的设计是非常灵活的,它在每一个http块、server块或location块下,都会生成独立的数据结构来存放配置项。 因此,我们允许当用户访问的请求不同时(如请求的URL分别是/url1、/url2、/url3),配置 项test_str可以具有不同的值。那么,当请求是/url1时,test_str的值应当是location块下的 loc1,还是这个location所属的server块下的server80,又或者是其所属http块下的值main呢? 完全由mytest模块自己决定,我们可以定义这个行为
参照一:如何自定义配置项处理办法和合并_编程界的谢菲尔德的博客-CSDN博客
问题二:
多个location块(或者http块、 server块)中的相同配置项是允许同时生效的,也就是说,我们刚刚定义的 ngx_http_mytest_conf_t结构必须在Nginx的内存中保存许多份。事实上,HTTP框架在解析 nginx.conf文件时只要遇到http{}、server{}或者location{}配置块就会立刻分配一个新的 ngx_http_mytest_conf_t结构体。因此,HTTP模块感兴趣的配置项需要统一地使用一个struct结 构体来保存(否则HTTP框架无法管理),如果nginx.conf文件中在http{}下有多个server{}或 者location{},那么这个struct结构体在Nginx进程中就会存在多份实例。
问题三:
HTTP框架定义了3个级别的配置main、srv、loc,分别表示直接出现在http{}、 server{}、location{}块内的配置项。当nginx.conf中出现http{}时,HTTP框架会接管配置文件 中http{}块内的配置项解析当遇到http{…}配置 块时,HTTP框架会调用所有HTTP模块可能实现的create_main_conf、create_srv_conf、 create_loc_conf方法生成存储main级别配置参数的结构体;在遇到server{…}块时会再次调用 所有HTTP模块的create_srv_conf;在遇到location{…}时则会再次调create_loc_conf回调方法生成存储loc级别配置参数的 结构体。因此,实现这3个回调方法的意义是不同的
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/129611.html