Nginx module开发 简单实例——filter模块

上篇笔记完成了一个简单的handler模块hello_module,本篇笔记将在上篇笔记的基础上增加一个filter模块,目的是将hanlder模块输出内容加粗变颜色。文章参考了http://tengine.taobao.org/book/chapter_04.html

 

一、filter模块介绍

        过滤(filter)模块是过滤响应头和内容的模块,可以对回复的头和内容进行处理。它的处理时间在获取回复内容之后,向用户发送响应之前。它的处理过程分为两个阶段,过滤HTTP回复的头部和主体,在这两个阶段可以分别对头部和主体进行修改。

   过滤模块中通常都有两个函数

ngx_http_top_header_filter(r);

ngx_http_top_body_filter(r, in);

      是分别对头部和主体进行过滤的函数。所有模块的响应内容要返回给客户端,都必须调用这两个接口。

       

      过滤模块的调用是有顺序的,它的顺序在编译的时候就决定了。可以在nginx源码所在路径的objs/ngx_modules.c文件中看到

 

模块的执行顺序是反向的。也就是说最早执行的是not_modified_filter,然后各个模块依次执行。所有第三方的过滤模块只能加入到copy_filter和headers_filter模块之间执行。可以看到编写的content_bold_filter模块就在它们之间。


所有filter模块头部过滤函数和主体过滤函数共同组成了一个链表结构。nginx为了按照次序来执行各个过滤模块,通常通过局部的全局变量和挂载函数完成

 

 

 

ngx_http_top_header_filter是一个全局变量。当编译进一个filter模块的时候,就被赋值为当前filter模块的处理函数。而ngx_http_next_header_filter是一个局部全局变量,它保存了编译前上一个filter模块的处理函数。所以整体看来,就像用全局变量组成的一条单向链表。

 

每个模块想执行下一个过滤函数,只要调用一下ngx_http_next_header_filter这个局部变量。而整个过滤模块链的入口,需要调用ngx_http_top_header_filter这个全局变量。ngx_http_top_body_filter的行为与header fitler类似。

 

用图形象表示

 

 

 

二、filter模块实战

filter模块很多地方都跟handler模块很像,首先,都需要定义模块指令配置、模块上下文、模块的定义。

 

 

 

 

与handler模块不一样的比如上面挂载函数的方式,一般都使用上面的写法,然后就是两个主要的过滤函数header_filter处理函数和body_filter处理函数

 

其实想将handler模块的字体加粗变色逻辑很简单,可以使用一些基本的html语言,设置一下style就行了,所以可以声明两个字符串表示html标签的头和尾

 

所以body_filter处理函数主要就是需要把handler输出链表的首尾加上这两个字符串以达成加粗变色的目的,而header_filter处理函数就是需要改变这个新的输出体的长度。

 

Body_filter处理函数

 

 

 

Header_filter处理函数

 

 

其他逻辑与handler模块大致相同,不再说明,详见代码

 

三、编译运行

和handler模块一样,首先要编写config文件,注意filter模块的config文件和handler不同,通常是这样

 

 

本例的写法

 

该config文件和ngx_http_content_filter_module.c共同放在/usr/local/nginx-1.10.2/test/ngx_http_content_filter_module中

 

进入nginx源码的目录/usr/local/nginx-1.10.2/ 执行./configure --prefix=/usr/local/nginx/ --add-module=/home/lyz/ngx_http_hello_world_module --add-module=/usr/local/nginx-1.10.2/test/ngx_http_content_bold_filter_module

然后make && make install

 

最后修改/usr/local/nginx/conf/nginx.conf加入content_bold指令

 

打开nginx,访问6.5.128.160:12345/hello可以看到

 

加粗变红,完成。

 

#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

/** 模块的配置结构 */
typedef struct
{
    ngx_int_t bold_flag;
} ngx_http_bold_filter_loc_conf_t;

static ngx_int_t ngx_http_content_bold_init(ngx_conf_t *cf);
static void *ngx_http_content_bold_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_content_bold_string(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;

/** 模块指令,这里我们创建了一个配置指令content_bold */
static ngx_command_t ngx_http_content_bold_commands[] = {
   {
    ngx_string("content_bold"),
    /* 该指令只能出现在location块中,并且有一个参数 */
    NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
    /* 读取解析参数的回调函数 */ 
    ngx_http_content_bold_string, 
    NGX_HTTP_LOC_CONF_OFFSET, 
    offsetof(ngx_http_bold_filter_loc_conf_t, bold_flag), 
    NULL
   },
    ngx_null_command 
};

/*  * 该模块上下文的定义。 * ngx_http_content_bold_init:这个回调函数负责在读取完配置信息之后注册filter函数 
    * ngx_http_content_bold_create_loc_conf:此回调函数负责在读取location配置之后,创建模块配置结构的存储空间 */
static ngx_http_module_t ngx_http_content_bold_module_ctx = {
        NULL,                         
        ngx_http_content_bold_init,    
        NULL,                        
        NULL,                         
        NULL,                        
        NULL,                         
        ngx_http_content_bold_create_loc_conf,
        NULL                          
};

/* 该模块的定义,指定了该模块对应的指令、上下文及模块类型 */
ngx_module_t ngx_http_content_bold_filter_module = {
        NGX_MODULE_V1,
        &ngx_http_content_bold_module_ctx,  
        ngx_http_content_bold_commands,    
        NGX_HTTP_MODULE,             
        NULL,                         
        NULL,                        
        NULL,                       
        NULL,                     
        NULL,                        
        NULL,                      
        NULL,                       
        NGX_MODULE_V1_PADDING
};
static u_char header_str[30] = "<html><h1 style=\"color:red\">";
static u_char tail_str[13] = "</h1></html>";

/** * 请求体处理函数,过滤请求体功能主要是在这里完成的 * 这里主要是在输入链表的首位分别加上header_str和tail_str已达到加粗的目的 */
static ngx_int_t ngx_http_content_bold_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    ngx_chain_t *out;
    ngx_chain_t *last_chain_ele;
    ngx_buf_t *b;
    ngx_buf_t *e;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "content_bold filter");
    ngx_http_bold_filter_loc_conf_t * my_conf;
    /* 这里是获取该指令的配置信息 */
    my_conf = ngx_http_get_module_loc_conf(r, ngx_http_content_bold_filter_module);
    /* 如果没有配置content_bold或者值为off。则什么都不处理直接调用下一个body_filter */
    if (my_conf->bold_flag == NGX_CONF_UNSET || my_conf->bold_flag == 0) {
        return ngx_http_next_body_filter(r, in); 
    }
    /* 如果响应体内容为空,也什么都不做直接调用下一个body_filter */
    if (in == NULL) {
        return ngx_http_next_body_filter(r, in);
    }
    /** 为链表首尾结点申请内存 */
    out = ngx_pcalloc(r->pool, sizeof(ngx_chain_t));
    last_chain_ele = ngx_pcalloc(r->pool, sizeof(ngx_chain_t));
    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    e = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (out==NULL || b == NULL||e == NULL||last_chain_ele==NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    /* 为第一个结点赋值:header_str */
    b->pos = header_str;
    b->last = header_str + ngx_strlen(header_str);
    b->memory = 1; 
    b->last_buf = 0;
    out->buf = b;
    out->next = in;
    ngx_chain_t *last_but_one = ngx_pcalloc(r->pool, sizeof(ngx_chain_t));
    while(in) {
       if(in!=NULL){
             in->buf->last_buf = 0;
             last_but_one = in;
       }
       in = in -> next;
    }
    /* 为最后一个结点赋值:tail_str */
    e->pos = tail_str;
    e->last = tail_str + ngx_strlen(tail_str);
    e->memory = 1; 
    e->last_buf = 1;
    last_chain_ele->buf = e;
    last_but_one->next = last_chain_ele;
    return ngx_http_next_body_filter(r, out);
}

/** * 头部过滤函数,这里主要是更改content_length */
static ngx_int_t ngx_http_content_bold_header_filter(ngx_http_request_t *r)
{
  r->headers_out.content_length_n = r->headers_out.content_length_n+ ngx_strlen(header_str) + ngx_strlen(tail_str);
  return ngx_http_next_header_filter(r);
}

/** * 为该模块的配置结构申请存储空间 */
static void * ngx_http_content_bold_create_loc_conf(ngx_conf_t *cf)
{
    ngx_http_bold_filter_loc_conf_t* local_conf = NULL;
    local_conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_bold_filter_loc_conf_t));
    if (local_conf == NULL)
    {
        return NULL;
    }
    local_conf->bold_flag = NGX_CONF_UNSET;
    return local_conf;
}

/** * 解析指令参数 */
static char *ngx_http_content_bold_string(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_bold_filter_loc_conf_t* local_conf;
    local_conf = conf;
    char* rv = NULL;
    rv = ngx_conf_set_flag_slot(cf, cmd, conf);
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "bold_flag:%d", local_conf->bold_flag);
    return rv;
}

/** * 挂载header_filter处理函数和body_filter处理函数 */
static ngx_int_t ngx_http_content_bold_init(ngx_conf_t *cf)
{
    ngx_http_next_header_filter = ngx_http_top_header_filter;
    ngx_http_top_header_filter = ngx_http_content_bold_header_filter;
    ngx_http_next_body_filter = ngx_http_top_body_filter;
    ngx_http_top_body_filter = ngx_http_content_bold_body_filter;

    return NGX_OK;
}

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Windows 下给 nginx 添加 gzip_static_module 模块,需要重新编译 nginx。以下是具体步骤: 1. 安装 Visual Studio 首先需要安装 Microsoft Visual Studio,官网下载地址:https://visualstudio.microsoft.com/zh-hans/downloads/ 2. 下载 nginx 源码 从 nginx 官网下载最新的 nginx 源码:http://nginx.org/en/download.html 3. 解压 nginx 源码 解压下载的 nginx 源码到任意目录,如:C:\nginx-1.20.1 4. 安装 Perl nginx 的编译过程需要用到 Perl,需要安装 Perl。官网下载地址:https://www.perl.org/get.html 5. 安装 PCRE PCRE 是一个支持正则表达式的库,nginx 的编译过程需要用到。可以从这里下载最新的 PCRE:https://ftp.pcre.org/pub/pcre/ 将解压后的文件夹复制到 C 盘根目录,如:C:\pcre-8.44 6. 安装 zlib zlib 是一个压缩库,nginx 的编译过程需要用到。可以从这里下载最新的 zlib:https://zlib.net/ 将解压后的文件夹复制到 C 盘根目录,如:C:\zlib-1.2.11 7. 编辑 nginx 配置文件 在 C:\nginx-1.20.1 目录下找到 conf 目录,编辑 nginx.conf 文件,在 http 模块中添加以下内容: ``` gzip_static on; ``` 8. 编译 nginx 打开 Visual Studio,选择 “文件” -> “打开” -> “项目/解决方案”,找到 C:\nginx-1.20.1 目录下的 nginx.sln 文件,双击打开。 在 Visual Studio 中选择 “生成” -> “生成解决方案”,等待编译完成。 9. 替换旧的 nginx.exe 编译完成后,会在 C:\nginx-1.20.1\objs 目录下生成新的 nginx.exe 文件。将该文件替换旧的 nginx.exe 文件,重启 nginx 服务器即可。 注意:以上步骤仅适用于 Windows 平台下的编译和安装,Linux 平台下的编译和安装方法略有不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值