您的位置:首页 > 理论基础 > 计算机网络

nginx的HTTP模块编写

2015-01-24 10:50 204 查看
本文是学习《深入理解nginx -- 模块开发与架构解析》的读书笔记

nginx的模块分为4个大类型的模块:

事件模块

HTTP模块

邮件代理相关的mail模块

其他模块

开发HTTP模块流程

这里的HTTP模块是最简单最经常编写的模块,开发一个完整的简单的HTTP模块需要下面几个步骤(以模块名为ngx_http_mytest_module为例):

1 编写config文件(这是为了让nginx在configure过程能找到编写的模块)

下面是编写具体的模块代码结构

ngx_addon_name=ngx_http_mytest_module
HTTP_MODULES="$HTTP_MODULES
ngx_http_mytest_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"

编写一个HTTP过滤模块

  以向返回给用户的文本格式响应包体前加一段字符串"[my filter prefix]"为例,展示如何编写一个HTTP过滤模块。源代码来自于《深入理解Nginx》。

1.config文件的编写

  与前几篇博文的HTTP模块不同,HTTP过滤模块需要HTTP_FILTER_MODULES一项以把所有过滤模块一同编译,因此config写作:

ngx_addon_name=ngx_http_myfilter_module
HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES ngx_http_myfilter_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_myfilter_module.c"


  进行configure时,--add-module=PATH是一样的。

2 编写模块结构 ngx_http_mytest_module

这个是模块结构,其中起的作用是:

定义了模块的上下文结构

定义了模块命令结构

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,
NGX_MODULE_V1_PADDING
};

3 编写模块上下文结构 ngx_http_mytest_module_ctx

这个结构的意思就是nginx在触发了模块运行的时候,如何处理已经在其他http,server,location定义过的上下文

static
ngx_http_module_t ngx_http_mytest_module_ctx = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
这样之后才是模块的上下文和模块定义:





static ngx_http_module_t ngx_http_myfilter_module_ctx = {
NULL,
  ngx_http_myfilter_init,
NULL,
NULL,

NULL,
NULL,
ngx_http_myfilter_create_conf,
ngx_http_myfilter_merge_conf
};


ngx_http_myfilter_module_ctx





ngx_module_t ngx_http_myfilter_module = {
NGX_MODULE_V1,
 &ngx_http_myfilter_module_ctx,
ngx_http_mytest_commands,
NGX_HTTP_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_V1_PADDING
};


ngx_http_myfilter_module
  从模块上下文可以看出,过滤功能在模块完成配置项处理后开始,其初始化方法为ngx_myfilter_init()。

4 编写模块命令结构 ngx_http_mytest_commands

这个结构的意思就是nginx在配置文件中触发了哪些命令,其中指定了:

触发命令的回调函数

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,/*
static
char *
ngx_http_mytest(ngx_conf_t *cf,
ngx_command_t *cmd,
void *conf);
*/
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL
},
ngx_null_command
};

5 触发命令的回调函数 ngx_http_mytest

这个回调函数中可以设置对http请求的具体处理方法

static
char *
ngx_http_mytest(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_mytest_handler;
return NGX_CONF_OK;
}

6 对http请求的具体处理方法 ngx_http_mytest_handler

这个方法的参数中可以获取http请求结构,并且可以设置http返回

至此,一个http模块就可以完成了。

static
ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
{
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 World");
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = response.len;
r->headers_out.content_type = type;
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
ngx_buf_t *b;
b = ngx_create_temp_buf(r->pool, response.len);
if (b ==
NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_memcpy(b->pos, response.data, response.len);
b->last = b->pos + response.len;
b->last_buf = 1;
ngx_chain_t out;
out.buf = b;
out.next =
NULL;
return
ngx_http_output_filter(r, &out);
}

对应的各个步骤说明:

1 编写config文件

示例:

ngx_addon_name=ngx_http_mytest_module

HTTP_MODULES="HTTP M ODULESngx h ttp m ytest m odule"NGX A DDON S RCS=" NGX_ADDON_SRCS
$ngx_addon_dir/ngx_http_mytest_module.c"

HTTP_MODULES是设置HTTP需要加载的模块列表,在具体编译的时候会生成modules的数组,然后根据数组的先后顺序一个一个加载

2 ngx_http_mytest_module的结构类型是ngx_module_t

它的结构说明看:

https://github.com/jianfengye/nginx-1.0.14_comment/blob/master/src/core/ngx_conf_file.h

里面的ngx_module_s的结构

最主要记得是要设置上下文结构ctx和命令集commands

3 某块上下文ngx_http_mytest_module_ctx的结构类型是ngx_http_module_t

它的结构说明看:

https://github.com/jianfengye/nginx-1.0.14_comment/blob/master/src/http/ngx_http_config.h

这个结构是如果需要的话在读取,重载配置文件的时候定义的8个阶段

create_main_conf

create_srv_conf

create_loc_conf

preconfiguration

init_main_conf

merge_srv_conf

merge_loc_conf

postconfiguration

4 ngx_http_mytest_commands 是一个ngx_command_s的数组

ngx_command_s的结构说明看:

它的结构说明看:

https://github.com/jianfengye/nginx-1.0.14_comment/blob/master/src/core/ngx_conf_file.h

里面碰到的set回调函数,这个回调函数可以使用nginx预设的14个解析配置方法,或者使用自定义的方法

14个预设的解析配置方法有:

ngx_conf_set_flag_slot

ngx_conf_set_str_slot

ngx_conf_set_str_array_slot

ngx_conf_set_keyval_slot

ngx_conf_set_num_slot

ngx_conf_set_size_slog

ngx_conf_set_off_slot

ngx_conf_set_msec_slot

ngx_conf_set_sec_slot

ngx_conf_set_bufs_slot

ngx_conf_set_enum_slot

ngx_conf_set_bitmask_slot

ngx_conf_set_acccess_slot

ngx_conf_set_path_slot

5 触发命令的回调函数的解析配置方法格式如下:

char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

如果使用了上面的14个解析配置方法,就可以不用自己写这个方法了

如果是自己写这个配置解析方法,就需要写第六步

ngx_http_mytest_handler

它的函数定义如下:

static ngx_init_t ngx_http_mytest_handler(ngx_http_request_t *r)

使用ngx_http_request_t指针输入

在ngx_http_request指针中也可以设置HTTP返回

它的结构说明看:

https://github.com/jianfengye/nginx-1.0.14_comment/blob/master/src/http/ngx_http_request.h

一个具体的例子:

https://github.com/jianfengye/MyWorks/tree/master/nginx_module_mytest

/*
* Copyright (C) yejianfeng
*/
#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_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
};
static
ngx_http_module_t ngx_http_mytest_module_ctx = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
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,
NGX_MODULE_V1_PADDING
};
static
char *
ngx_http_mytest(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_mytest_handler;
return NGX_CONF_OK;
}
static
ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
{
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 World");
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = response.len;
r->headers_out.content_type = type;
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
ngx_buf_t *b;
b = ngx_create_temp_buf(r->pool, response.len);
if (b ==
NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_memcpy(b->pos, response.data, response.len);
b->last = b->pos + response.len;
b->last_buf = 1;
ngx_chain_t out;
out.buf = b;
out.next =
NULL;
return
ngx_http_output_filter(r, &out);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: