Nginx开发一个简单的HTTP过滤模块

开发一个HTTP过滤模块的步骤和相关知识跟开发一个普通的HTTP模块是类似的,只不过HTTP过滤模块的地位、作用与正常的HTTP过滤模块不同,它的工作是对发送给用户的HTTP响应包做一些加工。

本文将学习开发一个简单的HTTP过滤模块,它能够对Content-Type为text/plain的包体前加上前缀字符串prefix。

(一)过滤模块的调用顺序

过滤模块可以叠加,也就是说一个请求会被所有的HTTP过滤模块依次处理。

过滤模块的调用是有顺序的,它的顺序在编译的时候就决定了。控制编译的脚本位于auto/modules中,当你编译完Nginx以后,可以在objs目录下面看到一个ngx_modules.c的文件。打开这个文件,有类似的代码:


ngx_module_t *ngx_modules[] = {
        ...
        &ngx_http_write_filter_module,
        &ngx_http_header_filter_module,
        &ngx_http_chunked_filter_module,
        &ngx_http_range_header_filter_module,
        &ngx_http_gzip_filter_module,
        &ngx_http_postpone_filter_module,
        &ngx_http_ssi_filter_module,
        &ngx_http_charset_filter_module,
        &ngx_http_userid_filter_module,
        &ngx_http_headers_filter_module,
        &ngx_http_copy_filter_module,
        &ngx_http_range_body_filter_module,
        &ngx_http_not_modified_filter_module,
        NULL
};

write_filternot_modified_filter,模块的执行顺序是反向的。也就是说最早执行的是not_modified_filter,然后各个模块依次执行。所有第三方的模块只能加入到copy_filterheaders_filter模块之间执行。

在编译Nginx源码时,已经定义了一个由所有HTTP过滤模块组成的单链表,这个单链表是这样的:

链表的每一个元素都是一个C源代码文件,这个C源代码文件中有两个指针,分别指向下一个过滤模块(文件)的过滤头部和包体的方法(可理解为链表中的next指针)

过滤模块单链表示意图:

这里写图片描述

这两个指针的声明如下:

/*过滤模块处理HTTP头部的函数指针类型定义,它携带一个参数:请求*/
typedef ngx_int_t (*ngx_http_output_header_filter_pt)(ngx_http_request_t *r);
/*过滤模块处理HTTP包体的函数指针类型定义,它携带两个参数:请求、要发送的包体*/
typedef ngx_int_t (*ngx_http_output_body_filter_pt)
    (ngx_http_request_t *r, ngx_chain_t *chain);

在我们定义的第三方模块中则有如下声明:

/*用static修饰只在本文件生效,因此允许所有的过滤模块都有自己的这两个指针*/
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;

那么怎么将这个源文件(节点),插入到HTTP过滤模块组成的单链表中去呢?
Nginx采用头插法的办法,所有的新节点都插入在链表的开头:

//插入到头部处理方法链表的首部
ngx_http_next_header_filter=ngx_http_top_header_filter;
ngx_http_top_header_filter=ngx_http_myfilter_header_filter;
//插入到包体处理方法链表的首部
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_myfilter_body_filter;

其中两个top指针声明如下:

extern ngx_http_output_header_filter_pt ngx_http_next_header_filter;
extern ngx_http_output_body_filter_pt ngx_http_next_body_filter;

由于是头插法,这样就解释了,越早插入链表的过滤模块,就会越晚执行。


(二)开发一个简单的过滤模块

要开发一个简单的过滤模块,它的功能是对Content-Typetext/plain的响应添加一个前缀,类似于开发一个HTTP模块,它应该遵循如下步骤:

1.确定源代码文件名称,源代码所在目录创建config脚本文件,config文件的编写方式跟HTTP模块开发基本一致,不同的是需要将HTTP_MODULES改成HTTP_FILTER_MODULES

2.定义过滤模块。实例化ngx_module_t类型模块结构,因为HTTP过滤模块也是HTTP模块,所以其中的type成员也是NGX_HTTP_MODULE

3.处理感兴趣的配置项,通过设置ngx_module_t中的ngx_command_t数组来处理感兴趣的配置项。

4.实现初始化方法。初始化方法就是把本模块中处理HTTP头部的ngx_http_output_header_filter_pt方法和处理HTTP包体的ngx_http_output_body_filter_pt方法插入到过滤模块链表的首部。

5.实现4.中提到两个处理头部和包体的方法。

接下来按照上述步骤依次来实现:

2.1 确定源代码文件目录,编写config文件

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"

2.2 定义过滤模块,实例化ngx_module_t

/*定义过滤模块,ngx_module_t结构体实例化*/
ngx_module_t ngx_http_myfilter_module =
{
    NGX_MODULE_V1,                 /*Macro*/
    &ngx_http_myfilter_module_ctx,         /*module context*/
    ngx_http_myfilter_commands,           
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值