HelloWorld 是一个典型的 location 模块。什么是 location 模块?在 Nginx 中,根据作用域,有 main 模块、server 模块、location 模块。
在 HelloWorld 模块中有一个 ngx_http_hello_world_module 变量,用于定义模块。它是 ngx_module_t 类型。ngx_module_t 是 ngx_module_s 的别名,其定义如下:
struct ngx_module_s {
ngx_uint_t ctx_index;
ngx_uint_t index;
ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t spare2;
ngx_uint_t spare3;
ngx_uint_t version; // Nginx模块版本
void *ctx; // 上下文定义的地址
ngx_command_t *commands; // 命令定义地址
ngx_uint_t type; // 模块类型
ngx_int_t (*init_master)(ngx_log_t *log); // 初始化 master 时执行
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); // 退出 master 时执行
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;
};
在 HelloWorld 例子中:
// Structure for the HelloWorld module, the most important thing
ngx_module_t ngx_http_hello_world_module = {
NGX_MODULE_V1,
&ngx_http_hello_world_module_ctx,
ngx_http_hello_world_commands,
NGX_HTTP_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_V1_PADDING
};
看它的定义你就知道,它是用来填充前 7 个 fields 的。
NGX_MODULE_V1 0, 0, 0, 0, 0, 0, 1
我们的模块是 HTTP 模块,还可以开发 CORE 模块,或者 CONF 模块等等。
// ngx_http_config.h
#define NGX_HTTP_MODULE 0x50545448 /* "HTTP" */
// ngx_conf_file.h
#define NGX_CORE_MODULE 0x45524F43 /* "CORE" */
#define NGX_CONF_MODULE 0x464E4F43 /* "CONF" */
这个还是用来填充字段的,或者叫 padding、补白。
#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0
命令定义用到如下数据结构:
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;
};
一般类说会定义很多命令,但是在 HelloWorld 中只有一个命令。
static ngx_command_t ngx_http_hello_world_commands[] = {
{
ngx_string("hello_world"), // The command name
NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
ngx_http_hello_world, // The command handler
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_hello_world_loc_conf_t, output_words),
NULL
},
ngx_null_command
};
我们一个一个来看。
name 成员表示命令名称
type 是命令类型。它可以取如下的一个或多个值的“或”:
NGX_HTTP_MAIN_CONF
:可出现在 http 的主作用域;NGX_HTTP_SRV_CONF
:可出现在 http 的 server 作用域;NGX_HTTP_LOC_CONF
:可出现在 http 的 location 作用域;NGX_HTTP_UPS_CONF
:可出现在 http 的 upstream 作用域;NGX_HTTP_SIF_CONF
:which will allow the directive to be included in if statements at the server level. [参考]NGX_CONF_NOARGS
:指令没有参数;NGX_CONF_TAKE1
:指令读入1个参数;NGX_CONF_TAKE2
:指令读入2个参数;NGX_CONF_TAKE7
:指令读入7个参数;NGX_CONF_FLAG
:指令读入1个布尔型数据(“on”或“off”);NGX_CONF_1MORE
:指令至少读入1个参数;NGX_CONF_2MORE
:指令至少读入2个参数;
// ngx_http_config.h
#define NGX_HTTP_MAIN_CONF 0x02000000
#define NGX_HTTP_SRV_CONF 0x04000000
#define NGX_HTTP_LOC_CONF 0x08000000
#define NGX_HTTP_UPS_CONF 0x10000000
#define NGX_HTTP_SIF_CONF 0x20000000
#define NGX_HTTP_LIF_CONF 0x40000000
#define NGX_HTTP_LMT_CONF 0x80000000
// ngx_conf_file.h
#define NGX_CONF_NOARGS 0x00000001
#define NGX_CONF_TAKE1 0x00000002
#define NGX_CONF_TAKE2 0x00000004
#define NGX_CONF_TAKE3 0x00000008
#define NGX_CONF_TAKE4 0x00000010
#define NGX_CONF_TAKE5 0x00000020
#define NGX_CONF_TAKE6 0x00000040
#define NGX_CONF_TAKE7 0x00000080
// ngx_conf_file.h
#define NGX_CONF_TAKE12 (NGX_CONF_TAKE1|NGX_CONF_TAKE2)
#define NGX_CONF_TAKE13 (NGX_CONF_TAKE1|NGX_CONF_TAKE3)
#define NGX_CONF_TAKE23 (NGX_CONF_TAKE2|NGX_CONF_TAKE3)
#define NGX_CONF_TAKE123 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3)
#define NGX_CONF_TAKE1234 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3|NGX_CONF_TAKE4)
// ngx_conf_file.h
#define NGX_CONF_ARGS_NUMBER 0x000000ff
#define NGX_CONF_BLOCK 0x00000100
#define NGX_CONF_FLAG 0x00000200
#define NGX_CONF_ANY 0x00000400
#define NGX_CONF_1MORE 0x00000800
#define NGX_CONF_2MORE 0x00001000
#define NGX_CONF_MULTI 0x00002000
这里我们使用的是自己定义的回调函数,还可以使用 Nginx 提供的回调函数,比如:
conf 参数它有三个可能的取值,分别如下:
NGX_HTTP_MAIN_CONF_OFFSET
NGX_HTTP_SRV_CONF_OFFSET
NGX_HTTP_LOC_CONF_OFFSET
这可不是随意指定的,如果你的type
参数设置了NGX_HTTP_MAIN_CONF
,那么这里就要设置为NGX_HTTP_MAIN_CONF_OFFSET
。相应的,如果是NGX_HTTP_SRV_CONF
或NGX_HTTP_LOC_CONF
,那么这里就要设置为NGX_HTTP_SRV_CONF_OFFSET
和NGX_HTTP_LOC_CONF_OFFSET
。
表示数据具体保存在main_conf、srv_conf、loc_conf指向的结构体的哪个位置(offset偏移)。大家可能会问,这个main_conf等等怎么来的,nginx给我们挖的坑长得是个什么样子,这个我们在介绍ngx_http_hello_world_module_ctx会说到。
一个补充字段,一般不用的,填入NULL。只是对于某些特殊的处理函数,比如ngx_conf_set_enum_slot,会用这个指针来指向enum定义表。
最后不要忘了加上 ngx_null_command,以表示命令集合定义完成。
用到了 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);
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;
可看到有以下几个部分:
它们都是函数指针,都可以为 NULL,不过我们的模块里用到的是:
// Structure for the HelloWorld context
static ngx_http_module_t ngx_http_hello_world_module_ctx = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
ngx_http_hello_world_create_loc_conf,
ngx_http_hello_world_merge_loc_conf
};
这两个函数会在下一篇文章中介绍。
-
转载请注明来自柳大的CSDN博客:Blog.CSDN.net/Poechant
-