9. Nginx 模块开发:模块类型区别与实例代码详解

📅 2026/7/6 3:42:04
9. Nginx 模块开发:模块类型区别与实例代码详解
1. Nginx 模块化开发概述Nginx 的高性能与灵活扩展性源于其高度模块化的内部架构。从开发者的视角看每一个功能都由一个独立的模块实现模块在编译时被链接进 Nginx 核心或者通过--add-module方式在编译时动态加入。理解不同模块类型的职责、数据结构与钩子挂载方式是掌握 Nginx 自定义开发的基础。Nginx 模块在代码层面分为以下几大类核心模块提供全局配置与框架支撑如ngx_core_module。事件模块封装底层网络 I/O 模型如ngx_epoll_module。HTTP 模块按处理阶段进一步细分为Handler 模块、Filter 模块、Upstream 模块。Mail 模块处理邮件代理协议。Stream 模块负责四层 TCP/UDP 代理。各类模块在源码中的结构体定义、上下文注册方式、指令挂载位置均有差异。本文从实例出发逐一剖析每种模块的开发范式。2. 核心模块开发范式核心模块定义了 Nginx 的顶层配置结构并负责解析全局指令如worker_processes、error_log。开发核心模块时需要实现ngx_core_module_t类型的结构体并挂载create_conf等回调。一个最简单的核心模块示例staticngx_core_module_tngx_example_core_module_ctx{ngx_string(example),NULL,/* create_conf */NULL/* init_conf */};ngx_module_tngx_example_core_module{NGX_MODULE_V1,ngx_example_core_module_ctx,/* module context */NULL,/* module directives (ngx_command_t array) */NGX_CORE_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};核心模块的module type填写NGX_CORE_MODULE其上下文指针必须指向ngx_core_module_t。这类模块通常较底层开发自定义核心模块的场景较少但它是理解 Nginx 模块注册机制的起点。编译配置核心模块负责全局配置编译时添加到CORE_MODULESngx_addon_namengx_example_core_moduleCORE_MODULES$CORE_MODULESngx_example_core_moduleNGX_ADDON_SRCS$NGX_ADDON_SRCS$ngx_addon_dir/ngx_example_core_module.c3. 事件模块开发范式事件模块负责封装epoll、kqueue等系统调用向上层提供统一的异步事件接口。开发事件模块时需要实现ngx_event_module_t上下文并提供ngx_event_actions_t结构体中的回调函数如add、del、process_events。代码骨架如下staticngx_int_tngx_example_add_event(ngx_event_t*ev,ngx_int_tevent,ngx_uint_tflags){/* 将事件注册到底层 I/O 复用模型 */returnNGX_OK;}staticngx_int_tngx_example_process_events(ngx_cycle_t*cycle,ngx_msec_ttimer,ngx_uint_tflags){/* 等待并处理活跃事件 */returnNGX_OK;}staticngx_event_module_tngx_example_event_module_ctx{example_event_name,NULL,/* create configuration */NULL,/* init configuration */{ngx_example_add_event,NULL,/* del_connection */NULL,/* del_event */NULL,/* enable accept */NULL,/* disable accept */ngx_example_process_events,NULL,/* init */NULL/* done */}};ngx_module_tngx_example_event_module{NGX_MODULE_V1,ngx_example_event_module_ctx,NULL,/* 指令表 */NGX_EVENT_MODULE,/* module type */NULL,NULL,NULL,NULL,NULL,NULL,NGX_MODULE_V1_PADDING};事件模块的type成员为NGX_EVENT_MODULE上下文字段对应ngx_event_module_t。如果你希望 Nginx 支持新的 I/O 模型就需要实现一个事件模块通常与平台相关。编译配置事件模块封装 I/O 复用挂到EVENT_MODULESngx_addon_namengx_example_event_moduleEVENT_MODULES$EVENT_MODULESngx_example_event_moduleNGX_ADDON_SRCS$NGX_ADDON_SRCS$ngx_addon_dir/ngx_example_event_module.c4. HTTP 模块开发范式HTTP 模块是开发中最常接触的类型所有与 HTTP 请求处理相关的模块都属于这个范畴。在源码层面HTTP 模块分为三种角色Handler、Filter、Upstream它们在同一个NGX_HTTP_MODULE类型下通过不同的钩子挂载点和处理函数来区分。4.1 HTTP Handler 模块Handler 模块直接生成响应或转发请求是请求的最终“内容生产者”。开发一个简单的 handler 模块需要完成以下步骤定义模块指令表ngx_command_t可在配置中设置参数。实现 Handler 函数负责填充ngx_http_request_t并返回响应。在ngx_http_module_t上下文的postconfiguration或preconfiguration中将 Handler 挂载到对应location的阶段。一个完整的 handler 示例——输出“Hello, Nginx!”staticngx_int_tngx_example_handler(ngx_http_request_t*r){ngx_buf_t*b;ngx_chain_tout;if(r-method!NGX_HTTP_GETr-method!NGX_HTTP_HEAD){returnNGX_HTTP_NOT_ALLOWED;}r-headers_out.statusNGX_HTTP_OK;r-headers_out.content_length_n13;r-headers_out.content_typengx_palloc(r-pool,sizeof(ngx_str_t));if(r-headers_out.content_typeNULL){returnNGX_HTTP_INTERNAL_SERVER_ERROR;}r-headers_out.content_type-lensizeof(text/plain)-1;r-headers_out.content_type-data(u_char*)text/plain;bngx_create_temp_buf(r-pool,13);if(bNULL){returnNGX_HTTP_INTERNAL_SERVER_ERROR;}ngx_memcpy(b-pos,Hello, Nginx!,13);b-lastb-pos13;b-last_buf1;out.bufb;out.nextNULL;ngx_http_send_header(r);returnngx_http_output_filter(r,out);}staticngx_command_tngx_example_commands[]{{ngx_string(example),NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,ngx_http_set_slot,0,0,NULL},ngx_null_command};staticngx_http_module_tngx_example_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 */};ngx_module_tngx_example_module{NGX_MODULE_V1,ngx_example_module_ctx,ngx_example_commands,NGX_HTTP_MODULE,NULL,NULL,NULL,NULL,NULL,NULL,NGX_MODULE_V1_PADDING};Handler 必须返回具体的 HTTP 状态码并通过ngx_http_output_filter将响应链发送出去。同一个location只能有一个 Handler 最终处理请求即content handler这是 Handler 模块与 Filter 模块最核心的区别。4.2 HTTP Filter 模块Filter 模块在 Handler 生成响应后对输出进行二次加工例如 gzip 压缩、添加响应头、响应体替换等。Filter 模块通过插入到全局的ngx_http_output_filter_t过滤器链中工作多个 filter 可以叠加数据依次流经各 filter。开发一个简单的 filter 模块——在所有响应末尾追加一行注释staticngx_int_tngx_example_filter_body(ngx_http_request_t*r,ngx_chain_t*in){ngx_buf_t*b;ngx_chain_t*cl,*ln;constcharfooter[]\n!-- generated by example filter --;/* 将原始链暂存然后追加自定义内容 */bngx_create_temp_buf(r-pool,sizeof(footer)-1);if(bNULL){returnNGX_ERROR;}ngx_memcpy(b-pos,footer,sizeof(footer)-1);b-lastb-possizeof(footer)-1;b-last_buf1;clngx_alloc_chain_link(r-pool);if(clNULL){returnNGX_ERROR;}cl-bufb;cl-nextNULL;/* 将追加链挂到原始链末尾 */for(lnin;ln-next;lnln-next){/* void */}ln-nextcl;returnngx_http_next_body_filter(r,in);}staticngx_http_output_header_filter_pt ngx_http_next_header_filter;staticngx_http_output_body_filter_pt ngx_http_next_body_filter;staticngx_int_tngx_example_filter_init(ngx_conf_t*cf){ngx_http_next_header_filterngx_http_top_header_filter;ngx_http_top_header_filterngx_example_header_filter;ngx_http_next_body_filterngx_http_top_body_filter;ngx_http_top_body_filterngx_example_filter_body;returnNGX_OK;}Filter 模块的关键在于通过全局变量如ngx_http_top_body_filter将自身处理函数插入过滤器链顶端并在函数末尾调用ngx_http_next_body_filter将数据传递给下一个 filter。Filter 模块没有独占 location 的特性它们可以作用于所有经过的响应这是与 Handler 的本质区别。4.3 HTTP Upstream 模块Upstream 模块定义后端服务器组并提供负载均衡算法。严格来说普通的 Upstream 使用并不需要编写新的模块类型Nginx 内置的ngx_http_upstream_module已经提供了轮询、ip_hash等算法。但如果需要实现自定义的复杂负载均衡逻辑如加权一致性哈希、动态负载等就需要开发一个 Upstream 模块。开发 Upstream 模块的要点是实现ngx_http_upstream_peer_t接口中的get、free、notify等函数并在配置解析时将自定义 peer 结构挂载到 upstream 的peer.init回调中。以下示意自定义 peer 的骨架typedefstruct{ngx_http_upstream_peer_tpeer;ngx_array_tservers;/* 自定义服务器列表 *//* 其他自定义加权、哈希数据 */}ngx_example_upstream_peer_t;staticngx_int_tngx_example_upstream_get_peer(ngx_peer_connection_t*pc,void*data){ngx_example_upstream_peer_t*epdata;/* 根据自定义算法选择后端并填充 pc-sockaddr */...returnNGX_OK;}完整的 Upstream 模块需要注册为NGX_HTTP_MODULE类型并在postconfiguration中调用ngx_http_upstream_init_round_robin等初始化函数最后替换peer.init。此部分较复杂但思路仍是围绕ngx_http_upstream_peer_t实现算法。6. Stream 模块开发Stream 模块处理 TCP/UDP 四层代理自 1.9.0 起成为正式功能。从开发视角Stream 模块的类型为NGX_STREAM_MODULE上下文结构体为ngx_stream_module_t。与 HTTP 模块类似Stream 模块内部也可以区分 Handler如proxy_pass、Filter如stream_ssl_module和 Upstream。一个简单的 Stream handler 模块示例——实现 TCP echostaticngx_int_tngx_example_stream_handler(ngx_stream_session_t*s){ngx_connection_t*cs-connection;ngx_buf_t*b;ngx_chain_t*cl;/* 分配缓冲区 */bngx_create_temp_buf(c-pool,s-buffer-last-s-buffer-pos);if(bNULL){returnNGX_ERROR;}ngx_memcpy(b-pos,s-buffer-pos,s-buffer-last-s-buffer-pos);b-lastb-pos(s-buffer-last-s-buffer-pos);b-last_buf1;clngx_alloc_chain_link(c-pool);if(clNULL){returnNGX_ERROR;}cl-bufb;cl-nextNULL;/* 直接回写接收到的数据 */c-write-handlerngx_stream_write_filter;ngx_stream_top_filter(c-write,cl);returnNGX_OK;}staticngx_command_tngx_example_stream_commands[]{{ngx_string(stream_example),NGX_STREAM_SRV_CONF|NGX_CONF_NOARGS,ngx_stream_set_var,/* 简化示意 */0,0,NULL},ngx_null_command};staticngx_stream_module_tngx_example_stream_ctx{NULL,NULL,NULL,NULL,NULL,NULL,NULL};ngx_module_tngx_example_stream_module{NGX_MODULE_V1,ngx_example_stream_ctx,ngx_example_stream_commands,NGX_STREAM_MODULE,NULL,NULL,NULL,NULL,NULL,NULL,NGX_MODULE_V1_PADDING};Stream handler 与 HTTP handler 的流程高度相似只是操作的对象从ngx_http_request_t变成了ngx_stream_session_t模块类型也从NGX_HTTP_MODULE变为NGX_STREAM_MODULE。7. 模块类型区别总结模块类型模块类型常量上下文结构体主要任务开发重点核心模块NGX_CORE_MODULEngx_core_module_t解析全局指令、管理顶层配置create_conf与全局变量事件模块NGX_EVENT_MODULEngx_event_module_t封装 I/O 复用模型实现ngx_event_actions_t的回调HTTP HandlerNGX_HTTP_MODULEngx_http_module_t生成/转发 HTTP 响应实现content_handler独占 locationHTTP FilterNGX_HTTP_MODULEngx_http_module_t修改响应头/体链式处理插入ngx_http_top_body_filter链HTTP UpstreamNGX_HTTP_MODULEngx_http_module_t自定义负载均衡算法实现ngx_http_upstream_peer_tMail 模块NGX_MAIL_MODULEngx_mail_module_t邮件协议代理实现ngx_mail_protocol_tStream 模块NGX_STREAM_MODULEngx_stream_module_tTCP/UDP 四层代理实现handler/ filter类似 HTTP 但操作 session关键区别核心模块与事件模块属于底层支撑直接与框架和操作系统交互不直接处理应用层数据。HTTP 模块是应用开发的主体但内部 Handler、Filter、Upstream 三者的角色不可混淆Handler 独占 location 产生响应Filter 可叠加修改输出Upstream 定义后端集群策略。Mail 模块与Stream 模块分别用于邮件和四层代理开发范式与 HTTP 模块高度相似只是上下文和模块类型常量不同。开发时务必正确填写ngx_module_t中的type字段它决定了模块的初始化顺序和可用的钩子函数。8. 结语掌握 Nginx 模块的分类与开发套路能让你从“配置使用”跃迁到“定制扩展”。实际开发中HTTP Handler 和 Filter 是最常见的二次开发入口而 Upstream、Stream 则适用于需要自定义负载均衡或四层协议处理的场景。本文提供的代码骨架均为经过精简的最小可运行示例你可以在此基础上参照 Nginx 现有模块如ngx_http_proxy_module、ngx_http_gzip_module进行扩展快速上手 Nginx 模块化开发。