4.2.3 使用14种预设方法解析配置项

本节将以举例的方式说明如何使用这14种Nginx的预设配置项解析方法来处理我们感兴趣的配置项。下面仍然以4.2.1节生成的配置项结构体ngx_http_mytest_conf_t为例进行说明,其中会尽量把type成员的多种用法都涵盖到。

(1)ngx_conf_set_flag_slot

假设我们希望在nginx.conf中有一个配置项的名称为test_flag,它的后面携带1个参数,这个参数的取值必须是on或者off。我们将用4.2.1节中生成的ngx_http_mytest_conf_t结构体中的以下成员来保存:


ngx_flag_t my_flag;


先看一下ngx_flag_t的定义:


typedef intptr_t ngx_flag_t;


可见,ngx_flag_t与ngx_int_t整型是相当的。可以如下设置ngx_conf_set_flag_slot来帮助解析test_flag参数。


static ngx_command_t ngx_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_null_command

};


上段代码表示,test_flag配置只能出现在location{……}块中(更多的type设置可参见表4-1)。其中,test_flag配置项的参数为on时,ngx_http_mytest_conf_t结构体中的my_flag会设为1,而参数为off时my_flag会设为0。

注意 在ngx_http_mytest_create_loc_conf创建结构体时,如果想使用ngx_conf_set_flag_slot,必须把my_flag初始化为NGX_CONF_UNSET宏,也就是4.2.1节中的语句mycf->test_flag=NGX_CONF_UNSET;,否则ngx_conf_set_flag_slot方法在解析时会报"is duplicate"错误。

(2)ngx_conf_set_str_slot

假设我们希望在nginx.conf中有一个配置项的名称为test_str,其后的参数只能是1个,我们将用ngx_http_mytest_conf_t结构体中的以下成员来保存它。


ngx_str_t my_str;


可以这么设置ngx_conf_set_str_slot来实现test_str的解析,如下所示。


static ngx_command_t ngx_http_mytest_commands[]={

……

{ngx_string("test_str"),

NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,

ngx_conf_set_str_slot,

NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_http_mytest_conf_t,my_str),

NULL},

ngx_null_command

};


以上代码表示test_str可以出现在http{……}、server{……}或者location{……}块内,它携带的1个参数会保存在my_str中。例如,有以下配置:


location……{

test_str apple;

}


那么,my_str的值为{len=5;data="apple";}。

(3)ngx_conf_set_str_array_slot

如果希望在nginx.conf中有多个同名配置项,如名称是test_str_array,那么每个配置项后都跟着一个字符串参数。这些同名配置项可能具有多个不同的参数值。这时,可以使用ngx_conf_set_str_array_slot预设方法,它将会把所有的参数值都以ngx_str_t的类型放到ngx_array_t队列容器中,如下所示。


static ngx_command_t ngx_http_mytest_commands[]={

……

{ngx_string("test_str_array"),

NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,

ngx_conf_set_str_array_slot,

NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_http_mytest_conf_t,my_str_array),

NULL},

ngx_null_command

};


在4.2.1节中已看到my_str_array是ngx_array_t*类型的。ngx_array_t数据结构的使用方法与ngx_list_t类似。本章不详细讨论ngx_array_t容器,感兴趣的读者可以直接阅读第6章查看ngx_array_t的使用特点。

上面代码中的test_str_array配置项也只能出现在location{……}块内。如果有以下配置:


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]和pstr[1]可以取到参数值,分别是{len=14;data="Content-Length";}和{len=16;data="Content-Encoding";}。从这里可以看到,当处理HTTP头部这样的配置项时是很适合使用ngx_conf_set_str_array_slot预设方法的。

(4)ngx_conf_set_keyval_slot

ngx_conf_set_keyval_slot与ngx_conf_set_str_array_slot非常相似,唯一的不同点是ngx_conf_set_str_array_slot要求同名配置项后的参数个数是1,而ngx_conf_set_keyval_slot则要求配置项后的参数个数是2,分别表示key/value。如果用ngx_array_t*类型的my_keyval变量存储以test_keyval作为配置名的参数,则必须设置NGX_CONF_TAKE2,表示test_keyval后跟两个参数。例如:


static ngx_command_t ngx_http_mytest_commands[]={

……

{ngx_string("test_keyval"),

NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,

ngx_conf_set_keyval_slot,

NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_http_mytest_conf_t,my_keyval),

NULL},

ngx_null_command

};


如果nginx.conf中出现以下配置项:


location……{

test_keyval Content-Type image/png;

test_keyval Content-Type image/gif;

test_keyval Accept-Encoding gzip;

}


那么,ngx_array_t*类型的my_keyval将会有3个成员,每个成员的类型如下所示。


typedef struct{

ngx_str_t key;

ngx_str_t value;

}ngx_keyval_t;


因此,通过遍历my_keyval就可以获取3个成员,分别是{"Content-Type","image/png"}、{"Content-Type","image/gif"}、{"Accept-Encoding","gzip"}。例如,取得第1个成员的代码如下。


ngx_keyval_t*pkv=mycf->my_keyval->elts;

ngx_log_error(NGX_LOG_ALERT,r->connection->log,0,

"my_keyval key=%s,value=%s,",

pkv[0].key.len,pkv[0].key.data,

pkv[0].value.len,pkv[0].value.data);


对于ngx_log_error日志的用法,将会在4.4节详细说明。

注意 在ngx_http_mytest_create_loc_conf创建结构体时,如果想使用ngx_conf_set_keyval_slot,必须把my_keyval初始化为NULL空指针,也就是4.2.1节中的语句mycf->my_keyval=NULL;,否则ngx_conf_set_keyval_slot在解析时会报错。

(5)ngx_conf_set_num_slot

ngx_conf_set_num_slot处理的配置项必须携带1个参数,这个参数必须是数字。我们用ngx_http_mytest_conf_t结构中的以下成员来存储这个数字参数如下所示。


ngx_int_t my_num;


如果用"test_num"表示这个配置项名称,那么ngx_command_t可以写成如下形式。


static ngx_command_t ngx_http_mytest_commands[]={

……

{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_null_command

};


如果在nginx.conf中有test_num 10;配置项,那么my_num变量就会设置为10。

注意 在ngx_http_mytest_create_loc_conf创建结构体时,如果想使用ngx_conf_set_num_slot,必须把my_num初始化为NGX_CONF_UNSET宏,也就是4.2.1节中的语句mycf->my_num=NGX_CONF_UNSET;,否则ngx_conf_set_num_slot在解析时会报错。

(6)ngx_conf_set_size_slot

如果希望配置项表达的含义是空间大小,那么用ngx_conf_set_size_slot来解析配置项是非常合适的,因为ngx_conf_set_size_slot允许配置项的参数后有单位,例如,k或者K表示Kilobyte,m或者M表示Megabyte。用ngx_http_mytest_conf_t结构中的size_t my_size;来存储参数,解析后的my_size表示的单位是字节。例如:


static ngx_command_t ngx_http_mytest_commands[]={

……

{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_null_command

};


如果在nginx.conf中配置了test_size 10k;,那么my_size将会设置为10240。如果配置为test_size 10m;,则my_size会设置为10485760。

ngx_conf_set_size_slot只允许配置项后的参数携带单位k或者K、m或者M,不允许有g或者G的出现,这与ngx_conf_set_off_slot是不同的。

注意 在ngx_http_mytest_create_loc_conf创建结构体时,如果想使用ngx_conf_set_size_slot,必须把my_size初始化为NGX_CONF_UNSET_SIZE宏,也就是4.2.1节中的语句mycf->my_size=NGX_CONF_UNSET_SIZE;,否则ngx_conf_set_size_slot在解析时会报错。

(7)ngx_conf_set_off_slot

如果希望配置项表达的含义是空间的偏移位置,那么可以使用ngx_conf_set_off_slot预设方法。事实上,ngx_conf_set_off_slot与ngx_conf_set_size_slot是非常相似的,最大的区别是ngx_conf_set_off_slot支持的参数单位还要多1个g或者G,表示Gigabyte。用ngx_http_mytest_conf_t结构中的off_t my_off;来存储参数,解析后的my_off表示的偏移量单位是字节。例如:


static ngx_command_t ngx_http_mytest_commands[]={

……

{ngx_string("test_off"),

NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,

ngx_conf_set_off_slot,NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_http_mytest_conf_t,my_off),

NULL},

ngx_null_command

};


如果在nginx.conf中配置了test_off 1g;,那么my_off将会设置为1073741824。当它的单位为k、K、m、M时,其意义与ngx_conf_set_size_slot相同。

注意 在ngx_http_mytest_create_loc_conf创建结构体时,如果想使用ngx_conf_set_off_slot,必须把my_off初始化为NGX_CONF_UNSET宏,也就是4.2.1节中的语句mycf->my_off=NGX_CONF_UNSET;,否则ngx_conf_set_off_slot在解析时会报错。

(8)ngx_conf_set_msec_slot

如果希望配置项表达的含义是时间长短,那么用ngx_conf_set_msec_slot来解析配置项是非常合适的,因为它支持非常多的时间单位。

用ngx_http_mytest_conf_t结构中的ngx_msec_t my_msec;来存储参数,解析后的my_msec表示的时间单位是毫秒。事实上,ngx_msec_t是一个无符号整型:


typedef ngx_uint_t ngx_rbtree_key_t;

typedef ngx_rbtree_key_t

ngx_msec_t;


ngx_conf_set_msec_slot解析的配置项也只能携带1个参数。例如:


static ngx_command_t ngx_http_mytest_commands[]={

……

{ngx_string("test_msec"),

NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,

ngx_conf_set_msec_slot,NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_http_mytest_conf_t,my_msec),

NULL},

ngx_null_command

};


如果在nginx.conf中配置了test_msec 1d;,那么my_msec会设置为1天之内的毫秒数,也就是86400000。

注意 在ngx_http_mytest_create_loc_conf创建结构体时,如果想使用ngx_conf_set_msec_slot,那么必须把my_msec初始化为NGX_CONF_UNSET_MSEC宏,也就是4.2.1节中的语句mycf->my_msec=NGX_CONF_UNSET_MSEC;,否则ngx_conf_set_msec_slot在解析时会报错。

(9)ngx_conf_set_sec_slot

ngx_conf_set_sec_slot与ngx_conf_set_msec_slot非常相似,只是ngx_conf_set_sec_slot在用ngx_http_mytest_conf_t结构体中的time_t my_sec;来存储参数时,解析后的my_sec表示的时间单位是秒,而ngx_conf_set_msec_slot为毫秒。


static ngx_command_t ngx_http_mytest_commands[]={

……

{ngx_string("test_sec"),

NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,

ngx_conf_set_sec_slot,

NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_http_mytest_conf_t,my_sec),

NULL},

ngx_null_command

};


如果在nginx.conf中配置了test_sec 1d;,那么my_sec会设置为1天之内的秒数,也就是86400。

注意 在ngx_http_mytest_create_loc_conf创建结构体时,如果想使用ngx_conf_set_sec_slot,那么必须把my_sec初始化为NGX_CONF_UNSET宏,也就是4.2.1节中的语句mycf->my_sec=NGX_CONF_UNSET;,否则ngx_conf_set_sec_slot在解析时会报错。

(10)ngx_conf_set_bufs_slot

Nginx中许多特有的数据结构都会用到两个概念:单个ngx_buf_t缓存区的空间大小和允许的缓存区个数。ngx_conf_set_bufs_slot就是用于设置它的,它要求配置项后必须携带两个参数,第1个参数是数字,通常会用来表示缓存区的个数;第2个参数表示单个缓存区的空间大小,它像ngx_conf_set_size_slot中的参数单位一样,可以不携带单位,也可以使用k或者K、m或者M作为单位,如"gzip_buffers 4 8k;"。我们用ngx_http_mytest_conf_t结构中的ngx_bufs_t my_bufs;来存储参数,ngx_bufs_t(12.1.3节ngx_http_upstream_conf_t结构体中的bufs成员就是应用ngx_bufs_t配置的一个非常好的例子)的定义很简单,如下所示。


typedef struct{

ngx_int_t num;

size_t size;

}ngx_bufs_t;


ngx_conf_set_bufs_slot解析后会把配置项后的两个参数转化成ngx_bufs_t结构下的两个成员num和size,其中size以字节为单位。例如:


static ngx_command_t ngx_http_mytest_commands[]={

……

{ngx_string("test_bufs"),

NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,

ngx_conf_set_bufs_slot,NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_http_mytest_conf_t,my_bufs),

NULL},

ngx_null_command

};


如果在nginx.conf中配置为test_bufs 4 1k;,那么my_bufs会设置为{4,1024}。

(11)ngx_conf_set_enum_slot

ngx_conf_set_enum_slot表示枚举配置项,也就是说,Nginx模块代码中将会指定配置项的参数值只能是已经定义好的ngx_conf_enum_t数组中name字符串中的一个。先看看ngx_conf_enum_t的定义如下所示。


typedef struct{

ngx_str_t name;

ngx_uint_t value;

}ngx_conf_enum_t;


其中,name表示配置项后的参数只能与name指向的字符串相等,而value表示如果参数中出现了name,ngx_conf_set_enum_slot方法将会把对应的value设置到存储的变量中。例如:


static ngx_conf_enum_t test_enums[]={

{ngx_string("apple"),1},

{ngx_string("banana"),2},

{ngx_string("orange"),3},

{ngx_null_string,0}

};


上面这个例子表示,配置项中的参数必须是apple、banana、orange其中之一。注意,必须以ngx_null_string结尾。需要用ngx_uint_t来存储解析后的参数,在4.2.1节中是用ngx_http_mytest_conf_t中的ngx_uint_t my_enum_seq;来存储解析后的枚举参数的。在设置ngx_command_t时,需要把上面例子中定义的test_enums数组传给post指针,如下所示。


static ngx_command_t ngx_http_mytest_commands[]={

……

{ngx_string("test_enum"),

NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,

ngx_conf_set_enum_slot,NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_http_mytest_conf_t,my_enum_seq),

test_enums},

ngx_null_command

};


这样,如果在nginx.conf中出现了配置项test_enum banana;,my_enum_seq的值是2。如果配置项test_enum出现了除apple、banana、orange之外的值,Nginx将会报"invalid value"错误。

(12)ngx_conf_set_bitmask_slot(ngx_conf_tcf,ngx_command_tcmd,void*conf);

ngx_conf_set_bitmask_slot与ngx_conf_set_enum_slot也是非常相似的,配置项的参数都必须是枚举成员,唯一的差别在于效率方面,ngx_conf_set_enum_slot中枚举成员的对应值是整型,表示序列号,它的取值范围是整型的范围;而ngx_conf_set_bitmask_slot中枚举成员的对应值虽然也是整型,但可以按位比较,它的效率要高得多。也就是说,整型是4字节(32位)的话,在这个枚举配置项中最多只能有32项。

由于ngx_conf_set_bitmask_slot与ngx_conf_set_enum_slot这两个预设解析方法在名称上的差别,用来表示配置项参数的枚举取值结构体也由ngx_conf_enum_t变成了ngx_conf_bitmask_t,但它们并没有区别。


typedef struct{

ngx_str_t name;

ngx_uint_t mask;

}ngx_conf_bitmask_t;


下面以定义test_bitmasks数组为例来进行说明。


static ngx_conf_bitmask_t test_bitmasks[]={

{ngx_string("good"),0x0002},

{ngx_string("better"),0x0004},

{ngx_string("best"),0x0008},

{ngx_null_string,0}

};


如果配置项名称定义为test_bitmask,在nginx.conf文件中test_bitmask配置项后的参数只能是good、better、best这3个值之一。我们用ngx_http_mytest_conf_t中的以下成员:


ngx_uint_t my_bitmask;


来存储test_bitmask的参数,如下所示。


static ngx_command_t ngx_http_mytest_commands[]={

……

{ngx_string("test_bitmask"),

NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,

ngx_conf_set_bitmask_slot,

NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_http_mytest_conf_t,my_bitmask),

test_bitmasks},

ngx_null_command

};


如果在nginx.conf中出现配置项test_bitmask best;,那么my_bitmask的值是0x8。

(13)ngx_conf_set_access_slot

ngx_conf_set_access_slot用于设置读/写权限,配置项后可以携带1~3个参数,因此,在ngx_command_t中的type成员要包含NGX_CONF_TAKE123。参数的取值可参见表4-2。这里用ngx_http_mytest_conf_t结构中的ngx_uint_t my_access;来存储配置项"test_access"后的参数值,如下所示。


static ngx_command_t ngx_http_mytest_commands[]={

……

{ngx_string("test_access"),

NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,

ngx_conf_set_access_slot,

NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_http_mytest_conf_t,my_access),

NULL},

ngx_null_command

};


这样,ngx_conf_set_access_slot就可以解析读/写权限的配置项了。例如,当nginx.conf中出现配置项test_access user:rw group:rw all:r;时,my_access的值将是436。

注意 在ngx_http_mytest_create_loc_conf创建结构体时,如果想使用ngx_conf_set_access_slot,那么必须把my_access初始化为NGX_CONF_UNSET_UINT宏,也就是4.2.1节中的语句mycf->my_access=NGX_CONF_UNSET_UINT;,否则ngx_conf_set_access_slot解析时会报错。

(14)ngx_conf_set_path_slot

ngx_conf_set_path_slot可以携带1~4个参数,其中第1个参数必须是路径,第2~4个参数必须是整数(大部分情形下可以不使用),可以参见2.4.3节中client_body_temp_path配置项的用法,client_body_temp_path配置项就是用ngx_conf_set_path_slot预设方法来解析参数的。

ngx_conf_set_path_slot会把配置项中的路径参数转化为ngx_path_t结构,看一下ngx_path_t的定义。


typedef struct{

ngx_str_t name;

size_t len;

size_t level[3];

ngx_path_manager_pt manager;

ngx_path_loader_pt loader;

void*data;

u_char*conf_file;

ngx_uint_t line;

}ngx_path_t;


其中,name成员存储着字符串形式的路径,而level数组就会存储着第2、第3、第4个参数(如果存在的话)。这里用ngx_http_mytest_conf_t结构中的ngx_path_t*my_path;来存储配置项"test_path"后的参数值。


static ngx_command_t ngx_http_mytest_commands[]={

……

{ngx_string("test_path"),

NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,

ngx_conf_set_path_slot,

NGX_HTTP_LOC_CONF_OFFSET,

offsetof(ngx_http_mytest_conf_t,my_path),

NULL},

ngx_null_command

};


如果nginx.conf中存在配置项test_path/usr/local/nginx/1 2 3;,my_path指向的ngx_path_t结构中,name的内容是/usr/local/nginx/,而level[0]为1,level[1]为2,level[2]为3。如果配置项是test_path/usr/local/nginx/;,那么level数组的3个成员都是0。