模块目录
可在nginx-1.20.1/下创建目录ext/,专门存放自定义模块
如添加HTTP模块mytest,则在ext/下创建目录mytest
mytest/├── config└── ngx_http_mytest_module.c
步骤
原则:保证与Nginx命名规则一致,且文件目录代码中模块命名一致(太长也不要纠结),
demo可修改成自定义模块名 以下全部基于项目目录/根目录:nginx-1.21.3/
一、创建相关文件目录
创建模块文件目录ngx_http_demo_module/
可在任意位置,推荐在
nginx-1.21.3/modules/或nginx-1.21.3/ext/中
创建模块代码文件ngx_http_demo_module.c
创建config文件config
二、编辑config文件
配合configure脚本
# 仅在configure执行时使用,一般设置为模块名称ngx_addon_name="ngx_http_demo_module"# 保存所有的HTTP模块名称,每个HTTP模块间由空格符相连,在重新设置HTTP_MODULES变量时,不要直接覆盖他,应该使用空格追加模块HTTP_MODULES="$HTTP_MODULES ngx_http_demo_module"# 指定扩展模块的源代码NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_demo_module.c"
三、编辑模块代码文件
- 使用
static来优化代码
1. 定义HTTP模块ngx_http_demo_module
static ngx_module_t ngx_http_demo_module = {NGX_MODULE_V1, // 固定&ngx_http_demo_module_ctx,ngx_http_demo_commands,NGX_HTTP_MODULE, // 固定NULL,NULL,NULL,NULL,NULL,NULL,NULL,NGX_MODULE_V1_PADDING // 固定};
2. 定义模块上下文结构ngx_http_demo_module_ctx
static ngx_http_module_t ngx_http_demo_module_ctx = {NULL, // preconfigurationNULL, // postconfigurationNULL, // create_main_confNULL, // init_main_confNULL, // create_srv_confNULL, // merge_srv_confNULL, // create_loc_confNULL, // merge_loc_conf};
3. 定义模块命令结构ngx_http_demo_commands
static ngx_command_t ngx_http_demo_commands[] = {{ngx_string("http_demo_module_test_cmd"),NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS,ngx_http_demo_set,NGX_HTTP_LOC_CONF_OFFSET,0,NULL},ngx_null_command // 固定, 类似C字符串'\0'};
4. 编写命令触发回调函数ngx_http_demo_set
// 声明static char *ngx_http_demo_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);// 定义static char *ngx_http_demo_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {ngx_http_core_loc_conf_t *clcf;clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);clcf->handler = ngx_http_demo_handler;return NGX_OK;}
5. 编写HTTP请求处理回调函数ngx_http_demo_handler
// 声明static ngx_int_t ngx_http_demo_handler(ngx_http_request_t *r);// 定义static ngx_int_t ngx_http_demo_handler(ngx_http_request_t *r) {return NGX_OK;}static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r){// 必须是 GET 获得 HEAD 方法if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))){return NGX_HTTP_NOT_ALLOWED;}// 丢弃请求中的包体ngx_int_t rc = ngx_http_discard_request_body(r);if (rc != NGX_OK){return rc;}ngx_str_t type = ngx_string("text/plain");ngx_str_t response = ngx_string("Hello mytest Module!\n");r->headers_out.status = NGX_HTTP_OK;r->headers_out.content_length_n = response.len;r->headers_out.content_type = type;// 发送HTTP头部rc = ngx_http_send_header(r);if (rc == NGX_ERROR || rc > NGX_OK || r->header_only){return rc;}// 构造包体ngx_buf_t *buf;buf = ngx_create_temp_buf(r->pool, response.len);if (buf == NULL){return NGX_HTTP_INTERNAL_SERVER_ERROR;}ngx_memcpy(buf->pos, response.data, response.len);buf->last = buf->pos + response.len;buf->last_buf = 1; // ?// 构造发送时的 ngx_chain_t 结构体ngx_chain_t out;out.buf = buf;out.next = NULL;// 发送包体return ngx_http_output_filter(r, &out);}
6. 添加头文件
核心3个文件,再缺什么补什么
#include <ngx_config.h>#include <ngx_core.h>#include <ngx_http.h>
6. 完整代码
ngx_http_mytest_module.c内容如下:
#include <ngx_config.h>#include <ngx_core.h>#include <ngx_http.h>// 回调函数static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r);static char *ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);static ngx_http_module_t ngx_http_mytest_module_ctx = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};static ngx_command_t ngx_http_mytest_commands[] = {{ngx_string("mytest"),NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS,ngx_http_mytest,NGX_HTTP_LOC_CONF_OFFSET,0,NULL,},ngx_null_command};ngx_module_t ngx_http_mytest_module = {NGX_MODULE_V1,&ngx_http_mytest_module_ctx,ngx_http_mytest_commands,NGX_HTTP_MODULE,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NGX_MODULE_V1_PADDING};// 处理nginx.conf配置项参数static char *ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){ngx_http_core_loc_conf_t *clcf;// 获取 mytest 配置项所属的配置块clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);// 如果请求的主机域名、URI与mytest配置项所在的配置块相匹配,调用该方法clcf->handler = ngx_http_mytest_handler;return NGX_OK;}static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r){// 必须是 GET 获得 HEAD 方法if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))){return NGX_HTTP_NOT_ALLOWED;}// 丢弃请求中的包体ngx_int_t rc = ngx_http_discard_request_body(r);if (rc != NGX_OK){return rc;}ngx_str_t type = ngx_string("text/plain");ngx_str_t response = ngx_string("Hello mytest Module!\n");r->headers_out.status = NGX_HTTP_OK;r->headers_out.content_length_n = response.len;r->headers_out.content_type = type;// 发送HTTP头部rc = ngx_http_send_header(r);if (rc == NGX_ERROR || rc > NGX_OK || r->header_only){return rc;}// 构造包体ngx_buf_t *buf;buf = ngx_create_temp_buf(r->pool, response.len);if (buf == NULL){return NGX_HTTP_INTERNAL_SERVER_ERROR;}ngx_memcpy(buf->pos, response.data, response.len);buf->last = buf->pos + response.len;buf->last_buf = 1; // ?// 构造发送时的 ngx_chain_t 结构体ngx_chain_t out;out.buf = buf;out.next = NULL;// 发送包体return ngx_http_output_filter(r, &out);}
四、编译HTTP模块
cd nginx-1.20.1/./configure --add-module=ext/mytest/ # 模块目录make && make install
编译过程
添加自定义模块目录路径:绝对路径or相对路径,如ext/ngx_http_demo_module/
./configure --add-module={MODULE_DIR_PATH}makesudo make install
修改Nginx配置
worker_processes 4;events {worker_connections 1024;}http {server {listen 8080;# http://192.168.132.128:8080/http_demolocation /http_demo {demo_cmd;}}}
五、测试HTTP模块
- 网页访问:127.0.0.1:8080/http_demo
- 命令行访问:
curl 127.0.0.1;8080/http_demo
