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

简单的http过滤模块

2016-05-01 17:37 323 查看
http过滤模块仅处理服务器发往客户端的http响应,不处理客户端发往服务器的http请求。

过滤模块的调用顺序

过滤链表

在编译nginx源码时,已经定义了一个由所有http过滤模块组成的单链表(每个元素都是一个独立的c源码文件。这个文件会通过两个static指针指向下一个文件中的过滤方法)

typedef ngx_int_t (*ngx_http_output_header_filter_pt)(ngx_http_request_t *r);
typedef ngx_int_t (*ngx_http_output_body_filter_pt)(ngx_http_request_t *r,ngx_chain_t *chain); //chain表示要发送的包体


http框架中定义的链表入口

extern ngx_http_output_header_filter_pt ngx_http_top_header_filter;
extern ngx_http_body_header_filter_pt ngx_http_top_body_filter;


过滤链表的顺序

每个http过滤模块的初始化方法都会把自己加入到单链表的首部

大多数官方http过滤模块都会把初始化方法放到postconfiguration指针中



http过滤模块的开发步骤

确定源代码文件名称

在源代码所在目录创建config脚本文件,在执行configure时将该目录添加进去。HTTP_FILTER_MODULES,当使用多个源代码文件实现1个http过滤模块时,需要在NGX_ADDON_SRCS变量中添加其他源代码文件

定义过滤模块。

处理感兴趣的配置项。

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

实现处理http头部的方法

实现处理http包体的方法

编译安装,修改nginx.conf文件并启动自定义过滤模块

http过滤模块的简单例子

在返回包体前加一段字符串 “[my fiter prefix]”





编写config文件

使用一个源文件实现此功能,源文件名为:ngx_http_myfilter_module.c

在该文件所在目录添加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"


配置项和上下文

首先,希望在nginx.conf中有一个控制当前http过滤模块是否生效的配置项 参数为on | off。建立ngx_http_myfilter_conf_t结构体来存储配置项,使用ngx_flag_t类型的enable变量来存储这个参数值

typedef struct{
ngx_flag_t enable;
}ngx_http_myfilter_conf_t;


下面的ngx_http_myfilter_create_conf用于分配存储配置项的结构体ngx_http_myfilter_conf_t;

static void* ngx_http_myfilter_create_conf(ngx_conf_t *cf){
ngx_http_myfilter_conf_t *mycf;

//创建存储配置项的结构体
mycf=(ngx_http_myfilter_conf_t *)ngx_pcalloc(cf->pool,sizeof(ngx_http_myfilter_conf_t));
if(mycf==NULL){
return NULL;
}
//ngx_flat_t 类型的变量。如果使用预设函数ngx_conf_set_flag_slot解析配置项参数,那么必须初始化为NGX_CONF_UNSET
mycf->enable=NGX_CONF_UNSET;

return mycf;
}


希望配置不止出现在location{…},还可以出现在server{…}或者http{…}

还需要实现一个配置项值得合并方法-ngx_http_myfilter_merge_conf

static char * ngx_http_myfilter_merge_conf(ngx_conf_t *cf,void *parent,void *child){
ngx_http_myfilter_conf_t *prev=(ngx_http_myfilter_conf_t*)parent;
ngx_http_myfilter_conf_t *conf=(ngx_http_myfilter_conf_t*)child;

//合并ngx_flat_t类型的配置项enable
ngx_conf_merge_value(conf->enable,prev->enable,0);

return NGX_CONF_OK;
}


再建立一个http上下文结构体ngx_http_myfilter_ctx_t,其中包括add_prefix整型成员,表示是否添加前缀

typedef struct{
ngx_int_t add_prefix;
}ngx_http_myfilter_ctx_t;


为0,表示不加;为1,表示加;为2,表示头已加过

HTTP头部处理方法在1个请求中只会被调用1次。但包体处理方法在1个请求中有可能被多次调用。

定义http过滤模块

定义模块前,需要先定义两个关键成员:ngx_command_t类型的commands数组和ngx_http_module_t类型的ctx 成员

定义ngx_http_myfilter_commands数组,处理配置项,将配置项解析到ngx_http_myfilter_conf_t上下文结构体的成员中



在定义ngx_http_module_t类型的ngx_http_myfilter_module_ctx时,需要将ngx_http_myfilter_create_conf回调方法放到create_loc_conf成员;中,ngx_http_myfilter_merge_conf回调方法则要放到merge_loc_conf成员中;

ngx_http_myfilter_init模块初始化方法放到postconfiguration。





有了ngx_command_t类型的commands数组和ngx_http_module_t类型的ctx之后,就可以定义ngx_http_myfilter_module过滤模块了



初始化http过滤模块

在定义ngx_http_myfilter_init方法时,首先需要定义静态指针ngx_http_next_header_filter,用于指向下一个过滤模块的http头部处理方法,定义静态指针ngx_http_next_body_filter,用于指向下一个过滤模块的http包体处理方法



处理请求中的http头部





处理请求的http包体



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: