本文将实现一个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编写步骤

  1. 编写模块基本结构。包括模块的定义,模块上下文结构,模块的配置结构等
  2. 实现 handler 的挂载函数。根据模块的需求选择正确的挂载方式。
  3. 编写 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);
}