1. 引言
摘要:深入解析 Nginx 模块开发的核心结构体
ngx_http_module_t,系统讲解 8 个回调函数的作用与调用时机,涵盖配置创建、合并、初始化及请求处理全流程。结合可编译运行的完整模块示例,助你从零掌握 Nginx HTTP 模块开发。
Nginx 以其高性能、高并发和模块化架构著称。对于想要扩展 Nginx 功能的开发者来说,编写 HTTP 模块是最常见的需求。而理解 ngx_http_module_t 结构体,正是掌握 Nginx HTTP 模块开发的第一道关卡。
这个结构体定义了模块在 Nginx 配置解析和初始化过程中的 8 个回调函数。本文将逐一剖析它们的作用、调用时机与协作关系,并结合一个可直接编译运行的完整模块示例,帮你彻底吃透这套机制。
2. ngx_http_module_t 结构体定义
首先,我们来看一下 ngx_http_module_t 在 Nginx 源码中的定义(位于 src/http/ngx_http_config.h 或相关头文件中):
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;
这个结构体包含了 8 个函数指针,它们被分为三组,分别对应 Nginx 配置的三个层级:
- Main(主配置):
create_main_conf和init_main_conf - Server(虚拟主机配置):
create_srv_conf和merge_srv_conf - Location(请求位置配置):
create_loc_conf和merge_loc_conf
另外两个是全局的钩子函数:
preconfiguration:在解析配置之前调用。postconfiguration:在解析配置之后调用。
3. 配置层级与回调函数分组
Nginx 的配置是分层的,理解这一点至关重要:
- Main(http 块):最顶层,影响所有虚拟主机。
- Server(server 块):定义虚拟主机,可以继承 Main 层的配置。
- Location(location 块):定义 URL 匹配规则,可以继承 Server 层的配置。
ngx_http_module_t 的回调函数正是围绕这三个层级设计的,用于创建和合并各层级的配置结构体。
3.1 三级配置在内存中的布局结构
理解 Nginx 三级配置在内存中的布局,是掌握配置继承机制的关键。Nginx 在解析配置时,会为每个 HTTP 模块在每个层级上分配独立的配置结构体,并通过 ngx_http_conf_ctx_t 将它们串联起来。
核心数据结构:ngx_http_conf_ctx_t
Nginx 使用 ngx_http_conf_ctx_t 来管理每个配置上下文中的模块配置指针数组。其定义如下(位于 src/http/ngx_http_config.h):
typedef struct {
void **main_conf; // 指向所有 HTTP 模块的 main 配置指针数组
void **srv_conf; // 指向所有 HTTP 模块的 srv 配置指针数组
void **loc_conf; // 指向所有 HTTP 模块的 loc 配置指针数组
} ngx_http_conf_ctx_t;
这个结构体是理解内存布局的核心枢纽。每个 http、server、location 块在解析时,都会创建一个独立的 ngx_http_conf_ctx_t 实例。
内存布局全景图
下面通过一张内存布局图来直观展示三级配置的存储结构:
关键要点
-
main_conf 指针共享:所有
server块和location块的main_conf指针都指向http块创建的main_conf数组。这意味着 Main 层级的配置在整个 HTTP 上下文中是全局唯一的。 -
srv_conf 指针传递:
location块的srv_conf指针指向其所属server块的srv_conf数组。这就是merge_loc_conf中prev参数的来源——它指向的是所属 server 块的配置结构体。 -
loc_conf 独立创建:每个
location块都会通过create_loc_conf创建自己独立的loc_conf数组。这也是为什么merge_loc_conf需要将当前 location 的配置与 server 层的配置进行合并。 -
模块索引定位:每个模块在
main_conf、srv_conf、loc_conf数组中的位置由ngx_http_modules数组中的索引决定。模块通过ngx_http_get_module_main_conf、ngx_http_get_module_srv_conf、ngx_http_get_module_loc_conf这三个宏来获取自己的配置结构体指针:
// 这三个宏的定义(简化版)
#define ngx_http_get_module_main_conf(r, module) \
(r->main_conf[module.ctx_index])
#define ngx_http_get_module_srv_conf(r, module) \
(r->srv_conf[module.ctx_index])
#define ngx_http_get_module_loc_conf(r, module) \
(r->loc_conf[module.ctx_index])
合并后的最终布局
以我们的 hello_string 指令为例,假设配置如下:
http {
hello_string "Global Hello"; # Main 层级
server {
# 未设置 hello_string,继承 Main 层
location /api {
hello_string "API Hello"; # Location 层级
}
location /web {
# 未设置 hello_string,继承 Server 层
}
}
}
合并后各层级配置结构体在内存中的最终状态为:
| 层级 | 配置结构体 | hello_string 值 | 来源 |
|---|---|---|---|
| Main | ngx_http_hello_main_conf_t | "Global Hello" | 用户显式配置 |
| Server | ngx_http_hello_srv_conf_t | "Global Hello" | merge_srv_conf 从 Main 继承 |
| Location /api | ngx_http_hello_loc_conf_t | "API Hello" | 用户显式配置 |
| Location /web | ngx_http_hello_loc_conf_t | "Global Hello" | merge_loc_conf 从 Server 继承 |
这种设计使得 Nginx 的配置既灵活又高效——每个层级只需存储自己真正需要的配置,未设置的字段通过合并函数从上层继承,避免了冗余存储。
下面通过流程图直观展示 hello_string 指令从 Main 到 Server 再到 Location 的继承与合并过程,清晰说明 merge_srv_conf 和 merge_loc_conf 函数的逻辑:
4. 回调函数详解与代码实例
为了演示,我们假设要开发一个名为 ngx_http_hello_module 的模块,它有一个配置指令 hello_string,可以在不同层级设置。
4.1 配置结构体定义
首先,我们需要定义三个配置结构体,分别对应三个层级:
// 主配置(http 块)
typedef struct {
ngx_str_t hello_string; // 默认问候语
} ngx_http_hello_main_conf_t;
// 虚拟主机配置(server 块)
typedef struct {
ngx_str_t hello_string;
} ngx_http_hello_srv_conf_t;
// 位置配置(location 块)
typedef struct {
ngx_str_t hello_string;
} ngx_http_hello_loc_conf_t;
4.2 create_main_conf
- 作用:为
http块(Main 层级)创建模块的配置结构体。 - 调用时机:在解析
http {}块时,为每个 HTTP 模块调用一次。 - 返回值:指向新创建的配置结构体的指针。如果失败,返回
NULL。
static void *
ngx_http_hello_create_main_conf(ngx_conf_t *cf)
{
ngx_http_hello_main_conf_t *conf;
// 使用 ngx_pcalloc 在 Nginx 的内存池中分配并清零结构体
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_main_conf_t));
if (conf == NULL) {
return NULL;
}
// 设置一个标志,表示该字段尚未被设置
conf->hello_string.len = NGX_CONF_UNSET_SIZE;
conf->hello_string.data = NULL;
return conf;
}
4.3 init_main_conf
- 作用:初始化 Main 层级的配置。当所有配置指令都解析完毕后,此函数被调用,用于处理那些未在配置文件中显式设置的字段,赋予它们默认值。
- 调用时机:在
create_main_conf之后,所有http块内的指令解析完成后调用。 - 返回值:成功返回
NGX_CONF_OK;失败返回描述错误的字符串。
static char *
ngx_http_hello_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_hello_main_conf_t *mconf = conf;
// 如果用户没有在 http 块中配置 hello_string,则设置默认值
if (mconf->hello_string.len == NGX_CONF_UNSET_SIZE) {
ngx_str_set(&mconf->hello_string, "Hello from Main!");
}
return NGX_CONF_OK;
}
4.4 create_srv_conf
- 作用:为
server块创建配置结构体。 - 调用时机:在解析每个
server {}块时调用。 - 返回值:指向新创建的配置结构体的指针。
static void *
ngx_http_hello_create_srv_conf(ngx_conf_t *cf)
{
ngx_http_hello_srv_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_srv_conf_t));
if (conf == NULL) {
return NULL;
}
conf->hello_string.len = NGX_CONF_UNSET_SIZE;
conf->hello_string.data = NULL;
return conf;
}
4.5 merge_srv_conf
- 作用:合并 Server 层级的配置。当一个
server块没有显式设置某个指令时,它会从 Main 层级(http块)继承配置。此函数负责实现这个继承逻辑。 - 调用时机:在
create_srv_conf之后,所有server块内的指令解析完成后调用。 - 参数:
prev:指向 Main 层级配置结构体的指针(即create_main_conf创建的)。conf:指向当前server块配置结构体的指针(即create_srv_conf创建的)。
- 返回值:成功返回
NGX_CONF_OK;失败返回错误字符串。
static char *
ngx_http_hello_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_hello_srv_conf_t *prev = parent;
ngx_http_hello_srv_conf_t *conf = child;
// ngx_conf_merge_str_value 是 Nginx 提供的便捷宏
// 如果 conf->hello_string 未被设置(值为 NGX_CONF_UNSET),则使用 prev 的值
ngx_conf_merge_str_value(conf->hello_string, prev->hello_string, "Hello from Server!");
return NGX_CONF_OK;
}
4.6 create_loc_conf
- 作用:为
location块创建配置结构体。 - 调用时机:在解析每个
location {}块时调用。 - 返回值:指向新创建的配置结构体的指针。
static void *
ngx_http_hello_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_hello_loc_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_loc_conf_t));
if (conf == NULL) {
return NULL;
}
conf->hello_string.len = NGX_CONF_UNSET_SIZE;
conf->hello_string.data = NULL;
return conf;
}
4.7 merge_loc_conf
- 作用:合并 Location 层级的配置。当一个
location块没有设置某个指令时,它会从所属的server块继承配置。 - 调用时机:在
create_loc_conf之后,所有location块内的指令解析完成后调用。 - 参数:
prev:指向所属server块配置结构体的指针。conf:指向当前location块配置结构体的指针。
- 返回值:成功返回
NGX_CONF_OK;失败返回错误字符串。
static char *
ngx_http_hello_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_hello_loc_conf_t *prev = parent;
ngx_http_hello_loc_conf_t *conf = child;
// 如果 location 块没有设置 hello_string,则从 server 块继承
ngx_conf_merge_str_value(conf->hello_string, prev->hello_string, "Hello from Location!");
return NGX_CONF_OK;
}
4.8 preconfiguration
- 作用:在 Nginx 开始解析
http块内的配置指令之前调用。通常用于注册新的配置指令、变量或向其他模块暴露接口。 - 调用时机:在所有
create_*_conf函数之前,解析http块时调用。 - 返回值:成功返回
NGX_OK;失败返回NGX_ERROR。
static ngx_command_t ngx_http_hello_commands[] = {
{
ngx_string("hello_string"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_MAIN_CONF_OFFSET | NGX_HTTP_SRV_CONF_OFFSET | NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_hello_main_conf_t, hello_string), // 注意:这里只是示例,实际需要更复杂的处理
NULL
},
ngx_null_command
};
static ngx_int_t
ngx_http_hello_preconfiguration(ngx_conf_t *cf)
{
// 在这里可以注册新的变量
ngx_http_variable_t *v;
v = ngx_http_add_variable(cf, &ngx_string("hello_variable"), 0);
if (v == NULL) {
return NGX_ERROR;
}
v->get_handler = ngx_http_hello_variable_get_handler;
v->data = 0;
return NGX_OK;
}
4.9 postconfiguration
- 作用:在所有配置解析完成、所有
merge_*_conf函数调用之后调用。这是模块初始化自身处理函数的最后时机,常用于将模块的handler挂载到 Nginx 的请求处理阶段。 - 调用时机:在
init_main_conf和所有merge_*_conf函数之后调用。 - 返回值:成功返回
NGX_OK;失败返回NGX_ERROR。
static ngx_int_t
ngx_http_hello_postconfiguration(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
// 获取核心模块的 main 配置
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
// 在 NGX_HTTP_CONTENT_PHASE 阶段添加我们的处理函数
h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_hello_handler;
return NGX_OK;
}
5. 实战:完整模块示例
下面提供一个可直接编译运行的 ngx_http_hello_module 完整代码,包含指令解析、请求处理函数和编译配置(config 文件)。将以下文件放入 Nginx 源码的 modules/ngx_http_hello_module/ 目录下即可编译。
5.1 模块源文件:ngx_http_hello_module.c
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
/* ========== 配置结构体定义 ========== */
typedef struct {
ngx_str_t hello_string;
} ngx_http_hello_main_conf_t;
typedef struct {
ngx_str_t hello_string;
} ngx_http_hello_srv_conf_t;
typedef struct {
ngx_str_t hello_string;
} ngx_http_hello_loc_conf_t;
/* ========== 指令解析函数 ========== */
static char *
ngx_http_hello_string(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_str_t *value = cf->args->elts;
ngx_str_t *field;
/* 根据指令所在层级,获取对应的配置字段 */
if (cmd->offset == NGX_HTTP_MAIN_CONF_OFFSET) {
field = &((ngx_http_hello_main_conf_t *) conf)->hello_string;
} else if (cmd->offset == NGX_HTTP_SRV_CONF_OFFSET) {
field = &((ngx_http_hello_srv_conf_t *) conf)->hello_string;
} else {
field = &((ngx_http_hello_loc_conf_t *) conf)->hello_string;
}
*field = value[1];
return NGX_CONF_OK;
}
/* ========== 指令定义 ========== */
static ngx_command_t ngx_http_hello_commands[] = {
{
ngx_string("hello_string"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
ngx_http_hello_string,
NGX_HTTP_MAIN_CONF_OFFSET | NGX_HTTP_SRV_CONF_OFFSET | NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL
},
ngx_null_command
};
/* ========== 配置创建与合并回调 ========== */
static void *
ngx_http_hello_create_main_conf(ngx_conf_t *cf)
{
ngx_http_hello_main_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_main_conf_t));
if (conf == NULL) {
return NULL;
}
conf->hello_string.len = NGX_CONF_UNSET_SIZE;
conf->hello_string.data = NULL;
return conf;
}
static char *
ngx_http_hello_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_hello_main_conf_t *mconf = conf;
if (mconf->hello_string.len == NGX_CONF_UNSET_SIZE) {
ngx_str_set(&mconf->hello_string, "Hello from Main!");
}
return NGX_CONF_OK;
}
static void *
ngx_http_hello_create_srv_conf(ngx_conf_t *cf)
{
ngx_http_hello_srv_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_srv_conf_t));
if (conf == NULL) {
return NULL;
}
conf->hello_string.len = NGX_CONF_UNSET_SIZE;
conf->hello_string.data = NULL;
return conf;
}
static char *
ngx_http_hello_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_hello_srv_conf_t *prev = parent;
ngx_http_hello_srv_conf_t *conf = child;
ngx_conf_merge_str_value(conf->hello_string, prev->hello_string, "Hello from Server!");
return NGX_CONF_OK;
}
static void *
ngx_http_hello_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_hello_loc_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_loc_conf_t));
if (conf == NULL) {
return NULL;
}
conf->hello_string.len = NGX_CONF_UNSET_SIZE;
conf->hello_string.data = NULL;
return conf;
}
static char *
ngx_http_hello_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_hello_loc_conf_t *prev = parent;
ngx_http_hello_loc_conf_t *conf = child;
ngx_conf_merge_str_value(conf->hello_string, prev->hello_string, "Hello from Location!");
return NGX_CONF_OK;
}
/* ========== 请求处理函数 ========== */
static ngx_int_t
ngx_http_hello_handler(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_buf_t *b;
ngx_chain_t out;
ngx_http_hello_loc_conf_t *hlcf;
u_char *response;
size_t len;
/* 只处理 GET 和 HEAD 请求 */
if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) {
return NGX_HTTP_NOT_ALLOWED;
}
/* 丢弃请求体 */
rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return rc;
}
/* 获取当前 location 的配置 */
hlcf = ngx_http_get_module_loc_conf(r, ngx_http_hello_module);
/* 构造响应内容 */
len = hlcf->hello_string.len + 1; /* +1 for newline */
response = ngx_pnalloc(r->pool, len);
if (response == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_memcpy(response, hlcf->hello_string.data, hlcf->hello_string.len);
response[hlcf->hello_string.len] = '\n';
/* 设置响应头 */
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = len;
r->headers_out.content_type.len = sizeof("text/plain") - 1;
r->headers_out.content_type.data = (u_char *) "text/plain";
/* 构造输出 buffer */
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
b->pos = response;
b->last = response + len;
b->memory = 1; /* 内容在内存中 */
b->last_buf = 1; /* 这是最后一个 buffer */
out.buf = b;
out.next = NULL;
/* 发送响应头 */
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
/* 发送响应体 */
return ngx_http_output_filter(r, &out);
}
/* ========== preconfiguration:注册变量 ========== */
static ngx_int_t
ngx_http_hello_variable_get_handler(ngx_http_request_t *r,
ngx_http_variable_t *v, uintptr_t data)
{
ngx_http_hello_loc_conf_t *hlcf;
hlcf = ngx_http_get_module_loc_conf(r, ngx_http_hello_module);
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = hlcf->hello_string;
return NGX_OK;
}
static ngx_int_t
ngx_http_hello_preconfiguration(ngx_conf_t *cf)
{
ngx_http_variable_t *v;
v = ngx_http_add_variable(cf, &ngx_string("hello_variable"), 0);
if (v == NULL) {
return NGX_ERROR;
}
v->get_handler = ngx_http_hello_variable_get_handler;
v->data = 0;
return NGX_OK;
}
/* ========== postconfiguration:挂载 handler ========== */
static ngx_int_t
ngx_http_hello_postconfiguration(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_hello_handler;
return NGX_OK;
}
/* ========== 模块上下文与模块定义 ========== */
static ngx_http_module_t ngx_http_hello_module_ctx = {
ngx_http_hello_preconfiguration, /* preconfiguration */
ngx_http_hello_postconfiguration, /* postconfiguration */
ngx_http_hello_create_main_conf, /* create main configuration */
ngx_http_hello_init_main_conf, /* init main configuration */
ngx_http_hello_create_srv_conf, /* create server configuration */
ngx_http_hello_merge_srv_conf, /* merge server configuration */
ngx_http_hello_create_loc_conf, /* create location configuration */
ngx_http_hello_merge_loc_conf /* merge location configuration */
};
ngx_module_t ngx_http_hello_module = {
NGX_MODULE_V1,
&ngx_http_hello_module_ctx, /* module context */
ngx_http_hello_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
5.2 编译配置文件:config
在模块目录下创建 config 文件,内容如下:
ngx_addon_name=ngx_http_hello_module
HTTP_MODULES="$HTTP_MODULES ngx_http_hello_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_module.c"
5.3 编译与测试
将上述两个文件放入 Nginx 源码目录下的 modules/ngx_http_hello_module/ 目录,然后执行以下命令编译:
# 在 Nginx 源码根目录下执行
./configure --add-module=modules/ngx_http_hello_module
make -j$(nproc)
sudo make install
编译完成后,在 nginx.conf 中添加如下配置:
http {
hello_string "Hello, Nginx Module World!";
server {
listen 80;
server_name localhost;
location /hello {
hello_string "Hello from /hello location!";
}
location / {
# 使用默认的 hello_string
}
}
}
启动 Nginx 后,测试效果:
# 访问 / 路径,将输出 Main 层级的默认问候语
curl http://localhost/
# 输出: Hello, Nginx Module World!
# 访问 /hello 路径,将输出 location 层级的问候语
curl http://localhost/hello
# 输出: Hello from /hello location!
这个完整的模块示例涵盖了指令解析、配置继承、请求处理函数、变量注册和 handler 挂载等核心环节,你可以直接编译运行来验证 Nginx 模块开发的全流程。
5.1 完整的模块定义
最后,我们将所有回调函数组合起来,定义我们的模块:
static ngx_http_module_t ngx_http_hello_module_ctx = {
ngx_http_hello_preconfiguration, /* preconfiguration */
ngx_http_hello_postconfiguration, /* postconfiguration */
ngx_http_hello_create_main_conf, /* create main configuration */
ngx_http_hello_init_main_conf, /* init main configuration */
ngx_http_hello_create_srv_conf, /* create server configuration */
ngx_http_hello_merge_srv_conf, /* merge server configuration */
ngx_http_hello_create_loc_conf, /* create location configuration */
ngx_http_hello_merge_loc_conf /* merge location configuration */
};
ngx_module_t ngx_http_hello_module = {
NGX_MODULE_V1,
&ngx_http_hello_module_ctx, /* module context */
ngx_http_hello_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
6. 总结
ngx_http_module_t 结构体是 Nginx HTTP 模块开发的核心。通过本文的讲解和代码实例,你应该已经掌握了这 8 个回调函数的作用和调用时机:
create_*_conf:负责为各层级分配配置结构体内存。init_main_conf:初始化 Main 层级的默认值。merge_*_conf:实现配置的继承机制,是 Nginx 配置灵活性的关键。preconfiguration:在配置解析前注册指令和变量。postconfiguration:在配置解析后挂载请求处理函数。
理解并正确实现这些回调,是编写健壮、可配置的 Nginx 模块的第一步。希望这篇教程能帮助你开启 Nginx 模块开发之旅。
461



被折叠的 条评论
为什么被折叠?



