本文将实现一个hello-handler,即访问访问nginx location /pg/hello,我们hello module会读取配置文件,以及输出数据返回给客户端
nginx.conf 配置
// nginx.conf server增加如下配置
location /pg/hello {
hello;
}
config文件
在nginx中,我们要编写自己的module,需要增加对应的config,执行./configure的时候会将我们的模块添加到nginx中
```shell
#文件路径 nginx/pg_module/ngx_http_hello_module/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"
handler编写步骤
- 编写模块基本结构。包括模块的定义,模块上下文结构,模块的配置结构等
- 实现 handler 的挂载函数。根据模块的需求选择正确的挂载方式。
- 编写 handler 处理函数。模块的功能主要通过这个函数来完成。 下面对照代码注释
#include <ngx_http.h>
#include <ngx_config.h>
#include <ngx_core.h>
typedef struct
{
ngx_slab_pool_t *shpool; //共享内存,用于统计
} ngx_http_hello_conf_t;
static void *ngx_http_hello_create_location_conf(ngx_conf_t *cf);
static char *ngx_http_hello_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
//ngx_string("hello_buf"), 对应参数名称
//NGX_CONF_TAKE1 对应conf参数个数
static ngx_command_t hello_commands[] = {
{
ngx_string("hello"),
NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS,
ngx_http_hello_set,
NGX_HTTP_LOC_CONF_OFFSET,
0, NULL
},
ngx_null_command
};
static ngx_http_module_t hello_ctx = {
NULL, //preconfiguration
NULL, //postconfiguration
NULL, //create main configuration
NULL, //init main configuration
NULL, //create server configuration
NULL, //merge server configuration
ngx_http_hello_create_location_conf, //create location configuration
NULL, //merge location configuration
};
ngx_module_t ngx_http_hello_module = {
NGX_MODULE_V1, //version
&hello_ctx, //module context
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
};
char *ngx_http_hello_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, "ngx_http_hello_set");
return NGX_CONF_OK;
}
void *ngx_http_hello_create_location_conf(ngx_conf_t *cf) {
ngx_http_hello_conf_t *conf;
conf = ngx_palloc(cf->pool, sizeof(ngx_http_hello_conf_t));
ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, "ngx_http_hello_create_location_conf");
return conf;
}
测试基础框架
执行如下命令后,出现打印后,我们基础module已经正常加载到nginx里了,接下来我们去赋值conf函数以及输出http内容到客户端
#!bin/bash
/root/work/c/nginx/configure --prefix=/root/work/c/nginx/install --with-http_addition_module --with-debug --add-module=/root/work/c/nginx/pg_module/ngx_http_hello_module
#输出如下
#。。。
#adding module in /root/work/c/nginx/pg_module/ngx_http_hello_module
#+ ngx_http_hello_module was configured
#。。。
make -j 2
make install
root@VM-4-11-debian:~/work/c/nginx# ./install/sbin/nginx -c conf/nginx.conf
nginx: [emerg] ngx_http_hello_create_location_conf
nginx: [emerg] ngx_http_hello_create_location_conf
nginx: [emerg] ngx_http_hello_create_location_conf
nginx: [emerg] ngx_http_hello_create_location_conf
nginx: [emerg] ngx_http_hello_set
nginx: [emerg] ngx_http_hello_create_location_conf
添加handler处理
添加下面函数后,make,make install后启动, 访问http://localhost:8080/pg/hello ,可看到日志,代表我们handler已经正常运行了
```c
char *ngx_http_hello_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, "ngx_http_hello_buf_set");
ngx_http_core_loc_conf_t *corecf;
corecf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
//新增处理函数,也可设置11个阶段中7个的任何一个
corecf->handler = ngx_http_hello_handler;
return NGX_CONF_OK;
}
static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r) {
ngx_log_error(NGX_LOG_EMERG, r->pool->log, ngx_errno, "ngx_http_hello_handler");
ngx_buf_t *b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
ngx_chain_t out;
out.buf = b;
out.next = NULL;
return ngx_http_output_filter(r, &out);
}
make -j 2 & make install
curl http://localhost:8080/pg/hello
tail -n 1000 install/logs/error.log
#2022/05/19 01:36:36 [emerg] 2460203#0: *9 ngx_http_hello_handler (17: File exists), client: 127.0.0.1, server: localhost, request: "GET /pg/hello HTTP/1.1", host: "127.0.0.1:8080"
添加输出到客户端
修改ngx_http_hello_handler函数后,访问对应url输出hello:ip
//添加头文件
#include <arpa/inet.h>
static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r) {
ngx_log_error(NGX_LOG_EMERG, r->pool->log, ngx_errno, "ngx_http_hello_handler");
u_char html[1024] = {0};
//需要客户端真实ip需要开启realip模块
struct sockaddr_in *cli_ip = (struct sockaddr_in*)r->connection->sockaddr;
strcat((char*)html, "hello:");
strcat((char*)html,(char*)inet_ntoa((struct in_addr)cli_ip->sin_addr));
int len = sizeof(html);
r->headers_out.status = 200;
ngx_str_set(&r->headers_out.content_type, "text/html");
ngx_http_send_header(r);
ngx_buf_t *b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
ngx_chain_t out;
out.buf = b;
out.next = NULL;
b->pos = html;
b->last = html+len;
b->memory = 1;
b->last_buf = 1;
return ngx_http_output_filter(r, &out);
}