Nginx自定义C模块需定义模块结构体、指令数组和handler函数,通过config文件声明并静态编译进Nginx,最后在nginx.conf中配置location启用hello_world指令。

在 Nginx 中编写一个自定义 C 模块,核心是遵循 Nginx 模块开发规范:定义模块结构体、实现指令处理函数、注册 handler(如 `content_handler`),并正确编译进 Nginx。下面以一个最简的 “Hello World” 响应模块为例,说明关键步骤和要点。
1. 创建模块源文件(hello_module.c)
模块需实现标准接口,包括模块上下文(`ngx_http_module_t`)、指令数组、模块定义等。以下是最小可运行版本:
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h><p>static char <em>ngx_http_hello_world(ngx_conf_t </em>cf, ngx_command_t <em>cmd, void </em>conf);
static ngx_int_t ngx_http_hello_world_handler(ngx_http_request_t *r);</p>
<p>// 指令定义:hello_world
static ngx_command_t ngx_http_hello_world_commands[] = {
{ ngx_string("hello_world"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_hello_world,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
ngx_null_command
};</p>
<p>// 模块上下文(空实现即可,因不涉及配置存储)
static ngx_http_module_t ngx_http_hello_world_module_ctx = {
NULL, // preconfiguration
NULL, // postconfiguration
NULL, // create main configuration
NULL, // init main configuration
NULL, // create server configuration
NULL, // merge server configuration
NULL, // create location configuration
NULL // merge location configuration
};</p>
<p>// 模块定义
ngx_module_t ngx_http_hello_world_module = {
NGX_MODULE_V1,
&ngx_http_hello_world_module_ctx, // module context
ngx_http_hello_world_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
};</p>
<p>// 指令解析函数:仅注册 handler
static char <em>
ngx_http_hello_world(ngx_conf_t </em>cf, ngx_command_t <em>cmd, void </em>conf)
{
ngx_http_core_loc_conf_t *clcf;</p>
<pre class="brush:php;toolbar:false;">clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_hello_world_handler;
return NGX_CONF_OK;
}
// 实际响应逻辑 static ngx_int_t ngx_http_hello_world_handler(ngx_http_request_t r) { ngx_int_t rc; ngx_buf_t b; ngx_chain_t out;
// 必须是 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;
}
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = sizeof("Hello, World!") - 1;
r->headers_out.content_type.len = sizeof("text/plain") - 1;
r->headers_out.content_type.data = (u_char *) "text/plain";
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
// 构造响应体
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
out.buf = b;
out.next = NULL;
b->pos = (u_char *) "Hello, World!";
b->last = b->pos + sizeof("Hello, World!") - 1;
b->memory = 1;
b->last_buf = 1;
return ngx_http_output_filter(r, &out);
}
2. 编写 config 文件(让 Nginx 构建系统识别模块)
在模块同级目录下新建 config 文件(无后缀),内容如下:
ngx_addon_name=ngx_http_hello_world_module HTTP_MODULES="$HTTP_MODULES ngx_http_hello_world_module" NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/hello_module.c"
该文件告诉 Nginx 编译脚本:模块名、归属 HTTP 模块类别、源码路径。
3. 编译进 Nginx(非动态加载)
Nginx 官方主干目前**不支持运行时动态加载第三方 C 模块**(1.9.11+ 虽有 `--add-dynamic-module`,但要求模块导出特定符号且需显式 `load_module`,稳定性与兼容性仍受限;生产推荐静态编译):
- 进入已解压的 Nginx 源码目录(如
nginx-1.24.0/) - 执行 configure,带上你的模块路径:
./configure --add-module=/path/to/your/hello_module_dir - 运行
make && sudo make install
4. 配置并启用模块
编辑 nginx.conf,在某个 location 中启用指令:
location /hello {
hello_world;
}重启 Nginx 后访问 http://localhost/hello 即可看到 Hello, World!。
注意:模块中所有内存分配(如 ngx_pcalloc)必须使用 r->pool 或 cf->pool,不可用标准 malloc;字符串操作一律用 u_char* 和 Nginx 提供的宏(如 ngx_str_t);错误返回值严格遵守 Nginx 约定(NGX_ERROR, NGX_DECLINED, NGX_OK 等)。











