Nginx 配置项参数解析
来源:互联网 发布:淘宝导出库存 编辑:程序博客网 时间:2024/06/01 22:43
在简单的http模块中,mytest
配置项后面没有跟任何参数。本篇博客学习讨论HTTP模块是怎样获得感兴趣的配置项。
处理http配置项可以分为下面4个步骤:
(1)创建数据结构用于存储配置项对应的参数。
(2)设定配置项在nginx.conf中出现时的限制条件与回调方法。
(3)实现第二步中的回调方法,或者使用Nginx框架预设的14个回调方法。
(4)合并不同级别的配置块中出现的同名配置项。
这四个步骤是通过ngx_http_module_t
以及ngx_command_t
有机的结合起来。
本例中将在nginx.conf
中添加一些配置项来自己编写模块进行解析。
worker_processes 1;events { worker_connections 1024;}http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; #gzip on; server { listen 80; server_name localhost; location = / { root html; index index.html index.htm; } location = /zxtest{ test_str "zhangxiaoha"; test_num 23; test_flag off; test_size 10k; mytest; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; }}
我们希望通过自己模块将配置项中的参数保存到数据结构中,并通过访问localhost/zxtest
将内容显示到浏览器上。
1.数据结构
用一个结构体来包含所有我们感兴趣的参数,上述配置文件中,有4个带配置项值的配置项,因此我们的结构体与之对应:
typedef struct{ ngx_str_t my_str; ngx_int_t my_num; ngx_flag_t my_flag; size_t my_size;}ngx_http_mytest_conf_t;
在陶辉老师的《深入理解Nginx》一书中为了说明14种预设配置项的解析方法,因此在结构体中包含了14个成员,我为了简单起见,就用了4个。
2.预设的配置项解析方法
配置项解析方法通过ngx_command_t中的char *(*set)(ngx_conf_t *cf,ngx_command_t*cmd,void *conf)
回调成员设置,关于ngx_command_t结构的详细声明见core/ngx_conf_file.h
。
Nginx有14种预设的配置项解析方式:
(1)ngx_conf_set_flag_slot
配置项的参数是on或者off,当为on时结构体中对应变量被设置为1,否则被设置为0。
本例中,我们希望在nginx.conf中有一个配置项的名称为test_flag
,并且它后面携带的参数是on或者off,
那么我们可以使用生成的ngx_http_mytest_conf_t结构体中的以下成员保存:
ngx_flag_t my_flag;
当test_flag
配置项的值为on时,结构体中my_flag的值将设置为1
(2)ngx_conf_set_str_slot
用来设置ngx_str_t
类型的变量。
(3)ngx_conf_set_str_array_slot
该方法会将同名配置项的参数以ngx_str_t
的类型存放到ngx_array_t队列容器中
例如nginx.conf
有如下配置:
location ...{ test_str_array Content-Length; test_str_array Content-Encoding;}
则my_str_array->nelts
的值是2,表示出现了两个test_str_array
配置项。
并且,my_str_array->elts
指向ngx_str_t
类型组成的数组。
因此,我们进行如下访问:
ngx_str_t*pstr = mycf->my_str_array->elts;//pstr[0].len=14//pstr[0].data="Content-Length"//pstr[1].len=16//pstr[1].data="Content-Encoding"
(4)ngx_conf_set_keyval_slot
与ngx_conf_set_str_array_slot
类似,只不过其数组元素是一个Key/Value
类型,
因此,test_keyval
配置项的后面需要跟两个参数,并且在command
中的type
参数指定为 NGX_CONF_TAKE2
这种key-value的结构体如下定义:
// ~/nginx/src/core/ngx_string.htypedef struct{ ngx_str_t key; ngx_str_t value;} ngx_keyval_t;
(5) ngx_conf_set_num_slot
处理带一个参数的配置项。
如果使用test_num
表示这个配置项名称,在nginx.conf中有如下:
location ...{ test_num 10}
则在结构体中ngx_int_t my_num
成员将会变成10
(6) ngx_conf_set_size_slot
配置项希望表达的含义是空间的大小,那么该回调函数就十分适合。
用结构体ngx_http_mytest_conf_t
中的size_t my_size
来存储参数。
如果配置了test_size 10k;
,则该参数将被设置成10240
(7)ngx_conf_set_off_slot
配置项表达的含义是空间的偏移位置,则使用该内置回调函数。
结果最终将保存在ngx_http_mytest_conf_t
的off_t my_off
成员中
(8)ngx_conf_set_msec_slot
解析之后将以毫秒的形式存储在ngx_http_mytest_conf_t
中的 ngx_msec_t my_msec;
成员中。
例如test_msec 1d
,将设置86400000,表示一天的毫秒数。
(9)ngx_conf_set_sec_slot
跟上述类似,单位是秒。
(10)ngx_conf_set_bufs_slot
配置项需要携带两个参数,第一个参数表示缓存区的个数,
第二个参数表示缓存区的大小。
用来保存这两个参数的是一个结构体变量:
// nginx/src/core/ngx_buf.htypedef struct{ ngx_int_t num; size_t size;}ngx_bufs_t;//区别 ngx_buf_t
(11)ngx_conf_set_enum_slot
nginx的enum类型定义如下:
//nginx/src/core/ngx_conf_file.htypedef struct { ngx_str_t name; ngx_uint_t value;}ngx_conf_enum_t;
事先定义一个ngx_conf_enum_t
类型的数组,作用类似于字典,例如:
static ngx_conf_enum_t test_enums[]={ {ngx_string("apple"),1}, ... ... {ngx_null_string,0}}
在nginx.conf
中配置项test_enum
的参数必须是上述数组中出现的,
否则,Nginx将会报错。而保存enum类型的是一个ngx_uint_t
类型的变量。
(12)ngx_conf_set_bitmask_slot
跟ngx_conf_enum_t
类似,需要事先定义一个ngx_conf_bitmask_t
类型的数组。
// nginx/core/src/ngx_conf_file.h typedef struct{ ngx_str_t name; ngx_uint_t mask;}ngx_conf_bitmask_t;
(13)ngx_conf_set_access_slot
用来设置读写权限。
(14)ngx_conf_set_path_slot
用来设置路径
3.创建与合并数据结构
在ngx_http_module_t
结构体中定义了8个回调函数(详见http/ngx_http_config.h
),其中:
typedef struct {//...//当需要创建数据结构用于存储main级别的全局配置项时,可以通过create_main_conf回调方法创建存储全局配置项的结构体 //(直属于http{}块的配置项) void *(*create_main_conf)(ngx_conf_t *cf); //初始化main级别配置项 char *(*init_main_conf)(ngx_conf_t *cf, void *conf); //创建存储srv级别配置项的结构体(server块) void *(*create_srv_conf)(ngx_conf_t *cf); //合并main级别和srv级别下的同名配置项 char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); //创建用于存储loc级别(直属于location{})的配置项 void *(*create_loc_conf)(ngx_conf_t *cf); //合并srv级别和location级别下的同名配置项 char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);}ngx_http_module_t;
有三组创建与合并的函数,目的是处理不同配置块中(http{} server{} location{}
)的配置项。
以loc级别的一组创建与合并的函数为例,create_loc_conf
回调函数用来主要为我们定义的结构体分配空间ngx_pcalloc
。 merge_loc_conf
回调函数用来合并server{}
配置块(相对于loc来说是parent)中的相同配置项的参数,nginx也提供相关的函数来指导怎样合并(例如以同一配置项是上一级别的参数为准,还是本级别的参数为准)。
4.自定义配置项处理函数
现在我们要自定义配置项处理方法,将我们从配置项中读出的参数输出到浏览器中(text/html)。
实际上,在Nginx开发简单的HTTP模块就使用了自定义的配置项处理方法,在《深入理解Nginx》中,作者自定义postconfiguration
回调在终端打印配置项参数信息。
这里我在自定义配置项处理的回调函数中ngx_conf_http_mytest
设置真正的处理工作的ngx_http_mytest_handler
,发送http响应。
5.完整代码
config文件
ngx_addon_name=ngx_http_mytest_moduleHTTP_MODULES="$HTTP_MODULES ngx_http_mytest_module"NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"
ngx_http_mytest_module.c
//ngx_http_mytest_module.c#include <ngx_config.h>#include <ngx_core.h>#include <ngx_http.h>static ngx_int_tngx_http_mytest_handler(ngx_http_request_t *r);static char *ngx_conf_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void* ngx_http_mytest_create_loc_conf(ngx_conf_t *cf);static char* ngx_http_mytest_merge_loc_conf(ngx_conf_t *cf,void *parent,void *child); //保存参数的数据结构typedef struct{ ngx_str_t my_str; ngx_int_t my_num; ngx_flag_t my_flag; size_t my_size;}ngx_http_mytest_conf_t;//合并loc级别的配置项参数static char* ngx_http_mytest_merge_loc_conf(ngx_conf_t *cf,void *parent,void *child){ ngx_http_mytest_conf_t *prev = parent; ngx_http_mytest_conf_t *conf = child; ngx_conf_merge_str_value(conf->my_str,prev->my_str,"defaultstr"); return NGX_CONF_OK; }//创建loc级别的配置项参数static void* ngx_http_mytest_create_loc_conf(ngx_conf_t *cf){ ngx_http_mytest_conf_t *conf; conf = ngx_pcalloc(cf->pool,sizeof(ngx_http_mytest_conf_t)); if(NULL == conf){ return NGX_CONF_ERROR; } conf->my_str.len = 0; conf->my_str.data = NULL; conf->my_flag = NGX_CONF_UNSET; conf->my_num = NGX_CONF_UNSET; conf->my_size = NGX_CONF_UNSET_SIZE; return conf; } //http模块山下文static ngx_http_module_tngx_http_mytest_module_ctx={ NULL, NULL, NULL, NULL, NULL, NULL, ngx_http_mytest_create_loc_conf, ngx_http_mytest_merge_loc_conf};//定义模块的配置文件参数static ngx_command_tngx_http_mytest_commands[]={ { ngx_string("test_flag"), NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_mytest_conf_t,my_flag), NULL }, { ngx_string("test_str"), //携带一个参数且可以出现在http/server/location配置块 NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, //nginx预设的方法 ngx_conf_set_str_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_mytest_conf_t, my_str), NULL }, { ngx_string("test_num"), NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, ngx_conf_set_num_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_mytest_conf_t, my_num), NULL }, { ngx_string("test_size"), NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_mytest_conf_t, my_size), NULL }, { ngx_string("mytest"), NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, ngx_conf_http_mytest, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL }, ngx_null_command};//nginx模块定义ngx_module_t ngx_http_mytest_module={ NGX_MODULE_V1, &ngx_http_mytest_module_ctx, ngx_http_mytest_commands, NGX_HTTP_MODULE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NGX_MODULE_V1_PADDING};//自定义配置项处理函数 static char*ngx_conf_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void*conf){ ngx_http_core_loc_conf_t *clcf; clcf=ngx_http_conf_get_module_loc_conf(cf,ngx_http_core_module);//handler是实际处理 clcf->handler=ngx_http_mytest_handler; return NGX_CONF_OK;}//handler回调 static ngx_int_tngx_http_mytest_handler(ngx_http_request_t *r){ //存储配置项参数 ngx_http_mytest_conf_t *elcf; elcf=ngx_http_get_module_loc_conf(r,ngx_http_mytest_module); if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD |NGX_HTTP_POST))) { return NGX_HTTP_NOT_ALLOWED; } //丢弃报文 ngx_int_t rc=ngx_http_discard_request_body(r); if(NGX_OK!=rc){ return rc; } //这里使用"text/html"如果使用"text/plain"浏览器会将下载文本当做bin文件下载下来 ngx_str_t type=ngx_string("text/html"); ngx_str_t format=ngx_string("helloworld,test_str=%v,test_flag=%i,test_num=%i,test_size=%z"); ngx_str_t test_str_arg=elcf->my_str; ngx_int_t test_num_arg=elcf->my_num; ngx_flag_t test_flag_arg=elcf->my_flag; size_t test_size_arg=elcf->my_size; int data_len=format.len+test_str_arg.len+1; r->headers_out.status=NGX_HTTP_OK; r->headers_out.content_length_n = data_len;//响应包包体内容长度 r->headers_out.content_type = type; rc=ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } ngx_buf_t *b; b = ngx_create_temp_buf(r->pool,data_len); if (b == NULL){ return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_snprintf(b->pos,data_len,(char *)format.data,&test_str_arg,test_flag_arg,test_num_arg,test_size_arg); b->last = b->pos + data_len; b->last_buf = 1; ngx_chain_t out; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); //发送响应报文}
6.测试
将模块编入nginx,重启nginx,在浏览器输入特定url,效果如下:
<
7.参考
1.《深入理解Nginx》(第二版)
2.http://blog.csdn.net/xiajun07061225/article/details/9147265
- Nginx 配置项参数解析
- Nginx配置项解析
- Nginx基础. Nginx配置解析
- Nginx配置参数说明
- Nginx配置参数说明
- nginx配置参数
- Nginx配置参数详解
- Nginx配置参数说明
- Nginx配置参数说明
- nginx 配置参数详解
- nginx一些参数配置
- nginx配置参数详解
- nginx配置参数详解
- Nginx配置参数
- Nginx配置参数详解
- Nginx主要配置参数
- Nginx配置解析
- Nginx配置解析
- 初用 Android Studio对自己需要的快捷键先小小记录
- 类的继承方式
- 数据仓库那点事
- 如何对比迁移前后的Oracle数据库性能
- OctoberCms 后端用户权限的设置
- Nginx 配置项参数解析
- 如何解决蓝屏代码0x000007B问题
- superTextView
- ExtJS 快速入门 - sencha cmd 常用命令
- android基础_第一天
- 如何使用junit4写单元测试用例
- 汇编——又一个Hello World!
- Maximum Depth of Binary Tree
- 安卓7.1 新特性Shortcut