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

Nginx学习(7)—http过滤模块(1)

2014-04-28 11:59 381 查看

HTTP过滤模块

为什么要使用过滤模块

HTTP过滤模块本质上也是一种HTTP模块,因此整个开发过程跟之前的《Hello Nginx!》是相似的。不同的是,过滤模块所做的工作只是对发送给用户的HTTP响应包做一些加工。
HTTP框架为HTTP请求的处理过程定义了11个阶段,相关代码:

[cpp] view
plaincopy





typedef enum {  

    NGX_HTTP_POST_READ_PHASE = 0,  

  

    NGX_HTTP_SERVER_REWRITE_PHASE,  

  

    NGX_HTTP_FIND_CONFIG_PHASE,  

    NGX_HTTP_REWRITE_PHASE,  

    NGX_HTTP_POST_REWRITE_PHASE,  

  

    NGX_HTTP_PREACCESS_PHASE,  

  

    NGX_HTTP_ACCESS_PHASE,  

    NGX_HTTP_POST_ACCESS_PHASE,  

  

    NGX_HTTP_TRY_FILES_PHASE,  

    NGX_HTTP_CONTENT_PHASE,          // 大部分HTTP模块只在此阶段处理  

  

    NGX_HTTP_LOG_PHASE  

} ngx_http_phases;  

一般而言,普通HTTP模块倾向于完成请求的核心功能(如static模块负责静态文件处理),而HTTP过滤模块则负责处理一些附加功能(如gzip压缩)。
过滤模块特性:

过滤模块效果可以根据需要叠加;
普通HTTP模块处理请求完毕,开始发送HTTP头或包体时,才开始依次调用过滤模块处理请求,因此,HTTP过滤模块只处理服务器发往客户端的响应,不处理客户端发往服务器的请求;

过滤模块顺序

在编译Nginx源码时,我们知道在ngx_modules.c文件中已经定义了一个模块数组,这个数组其实也就暗含了过滤模块的调用顺序。

过滤链表

所有HTTP过滤模块会构成一个单链表,链表的每一个元素都是一个独立的.c源文件。这个.c源文件会通过两个static静态指针(分别用于HTTP头和包体)指向下一个.c源文件。在ngx_http.c中定义两个指针,指向整个链表的首元素,也即第一个处理HTTP头和包体的方法。

[cpp] view
plaincopy





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);  

      

extern ngx_http_output_header_filter_pt  ngx_http_top_header_filter;  

extern ngx_http_output_body_filter_pt    ngx_http_top_body_filter;  

然后,在每一个过滤模块做初始化工作时,会先找到链表当前的首元素,然后再使用本身的static静态类型指针:

[cpp] view
plaincopy





static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;  

static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;  

将自己插入到链表首部,源码实现如下:

[cpp] view
plaincopy





static ngx_int_t  

ngx_http_XXX_filter_init(ngx_conf_t *cf)  

{  

    ngx_http_next_header_filter = ngx_http_top_header_filter;  

    ngx_http_top_header_filter = ngx_http_XXX_header_filter;  

      

    ngx_http_next_body_filter = ngx_http_top_body_filter;  

    ngx_http_top_body_filter = ngx_http_XXX_body_filter;  

      

    return NGX_OK;  

}  

当执行ngx_http_send_header发送HTTP头时,就开始遍历所有HTTP头部过滤模块了。

[cpp] view
plaincopy





ngx_int_t  

ngx_http_send_header(ngx_http_request_t *r)  

{  

    if (r->header_sent) {  

        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,  

                      "header already sent");  

        return NGX_ERROR;  

    }  

  

    if (r->err_status) {  

        r->headers_out.status = r->err_status;  

        r->headers_out.status_line.len = 0;  

    }  

  

    return ngx_http_top_header_filter(r);  

}  

HTTP包体链表类似。

过滤链表顺序

还是在编译Nginx源码时,编译进的ngx_modules.c模块数组,这个数组其实也就暗含了过滤模块的调用顺序。

首先,这个数组保存了所有的Nginx模块,包括HTTP普通模块与过滤模块,因此在初始化模块的顺序就按照这个该数组的成员顺序。又因为每个过滤模块都会将自己的初始化方法插入链表首部,因此过滤模块的调用顺序应该是数组中所有过滤模块的反向。具体的,结合书中内容,如下图:



过滤模块开发步骤

步骤基本与普通HTTP模块开发一致,概括总结如下:

增加.c源码文件;(HTTP过滤模块功能单一,一般一个.c文件即实现一个HTTP过滤模块)
在源码文件所在目录下创建config脚本文件,以便执行configure命令时将模块编译进Nginx;(与普通模块的config文件唯一不同就是HTTP_MODULES替换成HTTP_FILTER_MODULES)
定义过滤模块,即实例化ngx_module_t类型结构;
处理感兴趣的配置项,即设置ngx_command_t类型结构;
实现初始化方法,即插入单链表首部;
实现处理HTTP头部的方法;
实现处理HTTP包体的方法;
编译安装,修改nginx.conf文件并启动自定义过滤模块。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  nginx