参考资料<深入理解Nginx>

HTTP过滤模块也是一种HTTP模块,与普通HTTP处理模块不同在于:

1.一个请求仅由一个HTTP处理模块处理,而可以被任意个HTTP过滤模块处理

2.普通的HTTP模块倾向于完成请求的核心功能,而HTTP过滤模块所做的工作是对发送给用户的HTTP响应包做一些加工

 

HTTP过滤模块的简单例子

该过滤模块实现的功能是:用户的请求由static静态文件模块进行处理,根据URI返回磁盘中的文件给用户,然后该过滤模块就会在返回给用户的相应包体前添加一段字符串:"[my filter prefix]"

static静态文件模块处理完成后会调用ngx_http_send_header跟ngx_http_output_filter来调用过滤模块

1.编写config文件

跟普通HTTP模块不同的是HTTP_MODULES变量要改为HTTP_FILTER_MODULES

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.配置项与上下文

该过滤模块希望在nginx.conf中由一个控制当前HTTP过滤模块是否生效的配置项,它的参数值是on或者off。首先建立如下结构来存储配置项

typedef struct {
ngx_flag_t enable;
} ngx_http_myfilter_conf_t;

下面实现的ngx_http_myfilter_create_conf用于为存储配置项的结构体分配内存

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;
}
mycf->enable=NGX_CONF_UNSET;
return mycf;
}

因为Nginx的异步处理,一个HTTP包体处理方法在1个请求中可能被多次调用,而实际上我们只希望在包头加1次前缀。因此再建立一个HTTP上下文结构体来处理HTTP包体时是否添加前缀

typedef struct {
ngx_int_t add_prefix;
} ngx_http_myfilter_ctx_t;

3.定义HTTP过滤模块,与普通的HTTP模块类似,不多解释。

定义ngx_http_myfilter_commands数组,出现配置项是使用Nginx预设的方法ngx_conf_set_flag_slot来处理

static ngx_command_t ngx_http_myfilter_commands[]={
{
//配置项名称
ngx_string("add_prefix"),
//配置项类型(可出现的位置,参数的个数)
NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_FLAG,
//出现了name中指定的配置项后,将会调用该方法处理配置项的参数
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_myfilter_conf_t,enable),
NULL
},
ngx_null_command
};

定义ngx_http_module_t,ngx_http_myfilter_init方法用于初始化HTTP过滤模块,下面有它的实现代码

static ngx_http_module_t ngx_http_myfilter_module_ctx={
NULL,
ngx_http_myfilter_init,
NULL,
NULL,
NULL,
NULL,
ngx_http_myfilter_create_conf,
NULL
};

定义ngx_module_t

ngx_module_t ngx_http_myfilter_module={
NGX_MODULE_V1,
//指向ngx_http_module_t结构体
&ngx_http_myfilter_module_ctx,
//用来处理nginx.conf中的配置项
ngx_http_myfilter_commands,
//表示该模块的类型
NGX_HTTP_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_V1_PADDING
};

4.初始化HTTP过滤模块

一个请求可以由多个过滤模块处理,所以过滤模块是有调用顺序的,该方法用于构建过滤链表

//用于初始化HTTP过滤模块
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t ngx_http_myfilter_init(ngx_conf_t *cf)
{
//插入到头部处理方法链表的首部
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; return NGX_OK;
} static ngx_str_t filter_prefix = ngx_string("[filter_prefix]");

5.处理请求的HTTP头部

 static ngx_int_t
ngx_http_myfilter_header_filter(ngx_http_request_t *r)
{
ngx_http_myfilter_ctx_t *ctx;
ngx_http_myfilter_conf_t *conf;
//如果返回失败,则直接交由下一个过滤模块处理
if(r->headers_out.status!=NGX_HTTP_OK){
return ngx_http_next_header_filter(r);
}
//获取HTTP上下文
ctx=ngx_http_get_module_ctx(r,ngx_http_myfilter_module);
if(ctx){
//如果请求的上下文已经存在,说明ngx_http_myfilter_header_filter已经被调用过1次
return ngx_http_next_header_filter(r);
}
//获取存储配置项的ngx_http_myfilter_conf结构体
conf=ngx_http_get_module_loc_conf(r,ngx_http_myfilter_module);
//如果enable成员为0,则直接交给下一个
if(conf->enable==){
return ngx_http_next_header_filter(r);
}
//构造上下文结构体ngx_http_myfilter_ctx_t
ctx=ngx_pcalloc(r->pool,sizeof(ngx_http_myfilter_ctx_t));
if(ctx==NULL){
return NGX_ERROR;
}
//add_prefix为0表示不加前缀
ctx->add_prefix=;
//将构造的上下文设置到当前请求
ngx_http_set_ctx(r,ctx,ngx_http_myfilter_module);
//myfilter过滤模块只处理Content-Type是"text-plain"类型的HTTP响应
if(r->headers_out.content_type.len>=sizeof("text/plain")-
&& ngx_strncasecmp(r->headers_out.content_type.data,(u_char *)"text/plain",sizeof("text/plain")-)==)
{
//设置为1表示需要再HTTP包体前加入前缀
ctx->add_prefix=;
//把前缀字符串的长度加入Content-length中
if(r->headers_out.content_length_n>){
r->headers_out.content_length_n+=filter_prefix.len;
}
}
//交由下一个过滤模块继续处理
return ngx_http_next_header_filter(r);
}

6.处理请求的HTTP包体

 //处理请求中的HTTP包体
static ngx_int_t
ngx_http_myfilter_body_filter(ngx_http_request_t *r,ngx_chain_t *in)
{
ngx_http_myfilter_ctx_t *ctx;
ctx=ngx_http_get_module_ctx(r,ngx_http_myfilter_module);
//如果获取不到上下文,或者上下文结构体中add_prefix为0或2时,都不会添加前缀
if(ctx==NULL||ctx->add_prefix!=){
return ngx_http_next_body_filter(r,in);
}
//将add_prefix设置为2,防止重复添加前缀
ctx->add_prefix=;
//分配内存用于存储字符串前缀
ngx_buf_t *b=ngx_create_temp_buf(r->pool,filter_prefix.len);
//将ngx_buf_t中的指针指向filter_prefix字符串
b->start=b->pos=filter_prefix.data;
b->last=b->pos+filter_prefix.len;
//生成要发送的ngx_chain_t链表,加上刚分配的ngx_buf_t成员
ngx_chain_t *cl=ngx_alloc_chain_link(r->pool);
cl->buf=b;
cl->next=in;
//调用下一个过滤模块
return ngx_http_next_body_filter(r,cl);
}

 7.配置nginx.conf文件

添加如下配置,在nginx安装目录下添加txt/test.txt文件,访问localhost/test.txt。

location / {
root txt;
add_prefix on;
}

Nginx:HTTP过滤模块的更多相关文章

  1. Nginx 的过滤模块是干啥用的?

    上一篇文章我写了 Nginx 的 11 个阶段,很多人都说太长了.这是出于文章完整性的考虑的,11 个阶段嘛,一次性说完就完事了.今天这篇文章比较短,看完没问题. 过滤模块的位置 之前我们介绍了 Ng ...

  2. Nginx Http 过滤模块

    L69 执行顺序在content阶段后 log阶段前调用的 也就是处理完用户业务后 准备记录处理日志之前 我们可以到nginx http_model.c里查看 数组 执行顺序从下至上顺序执行 copy ...

  3. 《深入理解Nginx》阅读与实践(四):简单的HTTP过滤模块

    一.Nginx的HTTP过滤模块特征 一个请求可以被任意个HTTP模块处理: 在普通HTTP模块处理请求完毕并调用ngx_http_send_header()发送HTTP头部或调用ngx_http_o ...

  4. 简单的HTTP过滤模块

    简单的HTTP过滤模块 一.Nginx的HTTP过滤模块特征 一个请求可以被任意个HTTP模块处理: 在普通HTTP模块处理请求完毕并调用ngx_http_send_header()发送HTTP头部或 ...

  5. Nginx HttpSubModule sub_filter模块的过滤功能

    Nginx HttpSubModule sub_filter模块的过滤功能 发表于2年前(2013-08-05 10:39)   阅读(1481) | 评论(0) 0人收藏此文章, 我要收藏 赞0 5 ...

  6. 【Nginx】开发一个HTTP过滤模块

    与HTTP处理模块不同.HTTP过滤模块的工作是对发送给用户的HTTP响应做一些加工. server返回的一个响应能够被随意多个HTTP过滤模块以流水线的方式依次处理.HTTP响应分为头部和包体,ng ...

  7. Nginx之HTTP过滤模块

    1. HTTP 过滤模块 ngx_http_not_modified_module 仅对 HTTP 头部做处理.在返回 200 成功时,根据请求中 If-Modified-Since 或者 If-Un ...

  8. nginx图片过滤处理模块http_image_filter_module

    nginx图片过滤处理模块http_image_filter_module安装配置笔记 http_image_filter_module是nginx提供的集成图片处理模块,支持nginx-0.7.54 ...

  9. nginx日志模块与HTTP过滤模块与sub模块修改返回内容

    日志格式使用指令 指令介绍 Syntax: log_format name [escape=default|json|none] string ...; Default: log_format com ...

随机推荐

  1. Android 系统启动过程详解

    android 使用 linux 内核,一般运行在 ARM 体系架构上,android 设备启动的过程,应用层之下基本等同于linux, 从应用层第一个程序init开始有所区别,下面开始介绍. ste ...

  2. 150.Evaluate Reverse Polish Notation---逆波兰式求值

    题目链接 题目大意:计算逆波兰表达式的值. 法一:stack,用stack存数,遇到操作符,则运算.代码如下(耗时12ms): public int evalRPN(String[] tokens) ...

  3. centos7部署nagios

    一.Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机等.在系统或服务状态异常时发出邮件或短信报 ...

  4. MSSQL取得或删除重复数据

    1.取得不重复的数据 select * from Persons where Id in ( SELECT MAX(Id) AS Expr1 FROM Persons GROUP BY Name, G ...

  5. 如何打造属于自己的Javascript武器库(封装方法)

    前言 代码写的久了,就会发现很多时候都是在写一些重复的东西,这个时候就应该要考虑到提高工作效率了,比如对常用方法的封装,例如日期格式化,浏览器类型判断等. 今天这篇文章我们就来看看如何封装常用的Jav ...

  6. 元素类型 “meta” 必须由匹配的结束标记 “” 终止

    报错 org.xml.sax.SAXParseException: 元素类型 “meta” 必须由匹配的结束标记 “” 终止 系统自动创建 <meta charset="UTF-8&q ...

  7. Wannafly挑战赛10 D 小H的询问(线段树)

    题目链接  Problem D 这个题类似 SPOJ GSS3 做过那个题之后其实就可以秒掉这题了. 考虑当前线段树维护的结点 在那道题的基础上,这个题要多维护几个东西,大概就是左端点的奇偶性,右端点 ...

  8. spark完整的数据倾斜解决方案

    1.数据倾斜的原理 2.数据倾斜的现象 3.数据倾斜的产生原因与定位 在执行shuffle操作的时候,大家都知道,我们之前讲解过shuffle的原理. 是按照key,来进行values的数据的输出.拉 ...

  9. adb 查看android手机中应用的包名和安装位置

    1. 查看是否连接手机 adb devices 2. 进入指定的device的shell adb shell 或者 adb -s ********* shell 3. adb 查看所有安装的包 pm ...

  10. Maximum Size Subarray Sum Equals k -- LeetCode

    Given an array nums and a target value k, find the maximum length of a subarray that sums to k. If t ...