nginx源码分析——filter模块
2019独角兽企业重金招聘Python工程师标准>>>
1. filter模块简介
在nginx中,明确将HTTP响应分为两个部分——HTTP头部和HTTP包体,而filter模块的主要作用就是对HTTP响应信息进行加工处理。filter模块在NGX_HTTP_CONTENT_PHASE阶段参与处理(HTTP多阶段处理可参考这里),并且是在HTTP请求处理完毕后,才对HTTP头部和HTTP包体进行加工处理。有的filter模块仅对HTTP头部进行加工处理,有的仅对HTTP包体进行处理,也有的同时对HTTP头部和HTTP包体进行处理。另外,每个http请求都会被任意多个filter模块进行处理。也就是说,filter模块的处理效果是叠加的。例如,通过ngx_http_gzip_filter_module进行压缩处理后,再通过ngx_http_chunked_filter_module将响应包体以chunked编码形式发送。
2. filter模块
1). filter模块链表
通过调用ngx_http_send_header和ngx_http_output_filter发送HTTP头部、HTTP包体,最终会依次调用各个filter模块的处理函数完成对HTTP头部和HTTP包体的处理。
多个filter模块组成一个链表协同进行工作,而链表的实现则是通过四个函数指针来完成的。
其中ngx_http_top_header_filter和ngx_http_top_body_filter为全局变量,即ngx_http_send_header、ngx_http_output_filter只会调用这两个全局变量。
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);ngx_http_output_header_filter_pt ngx_http_top_header_filter;
ngx_http_output_body_filter_pt ngx_http_top_body_filter;ngx_int_t ngx_http_send_header( ngx_http_request_t * r )
{if( r->post_action ) {return NGX_OK;}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);
}ngx_int_t ngx_http_output_filter( ngx_http_request_t * r, ngx_chain_t * in )
{ngx_int_t rc;ngx_connection_t * c;c = r->connection;ngx_log_debug2( NGX_LOG_DEBUG_HTTP, c->log, 0, "http output filter \"%V?%V\"", &r->uri, &r->args );rc = ngx_http_top_body_filter(r, in);if( rc == NGX_ERROR ) {c->error = 1;}return rc;
}
ngx_http_next_header_filter和ngx_http_next_body_filter则是每个filter模块内部的静态变量,用于指向下一个filter模块的处理函数。通常是在http模块的postconfiguration处理中进行初始化。这样就形成了一个链表。
// ngx_http_chunked_filter_module.c
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_top_filter_pt ngx_http_next_body_filter;static ngx_int_t ngx_http_chunked_filter_init( ngx_conf_t * cf )
{ngx_http_next_header_filter = ngx_http_top_header_filter;ngx_http_top_headr_filter = ngx_http_chunked_header_filter;ngx_http_next_body_filter = ngx_http_top_body_filter;ngx_http_top_body_filter = ngx_http_chunked_body_filter;return NGX_OK;
}// ngx_http_gzip_filter_module.c
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_top_filter_pt ngx_http_next_body_filter;static ngx_int_t ngx_http_gzip_filter_init( ngx_conf_t * cf )
{ngx_http_next_header_filter = ngx_http_top_header_filter;ngx_http_top_headr_filter = ngx_http_chunked_header_filter;ngx_http_next_body_filter = ngx_http_top_body_filter;ngx_http_top_body_filter = ngx_http_chunked_body_filter;return NGX_OK;
}
每个filter模块处理完毕后,通过调用ngx_http_next_header_filter或者ngx_http_next_body_filter,交由下一个filter模块进行处理。
static ngx_int_t ngx_http_chunked_header_filter(ngx_http_request_t * r)
{ngx_http_core_loc_conf_t * clcf;ngx_http_chunked_filter_ctx_t * ctx;if( r->headers_out.status == NGX_HTTP_NOT_MODIFIED|| r->headers_out.status == NGX_HTTP_NO_CONTENT|| r->headers_out.status < NGX_HTTP_OK|| r != r->main|| r->method == NGX_HTTP_HEAD ){return ngx_http_next_header_filter(r);}if( r->headers_out.content_length_n == -1 ) {if( r->http_version < NGX_HTTP_VERSION_11 ) {r->keepalive = 0;} else {clcf = ngx_http_get_module_loc_conf( r, ngx_http_core_module );if( clcf->chunked_transfer_encoding ) {r->chunked = 1;ctx = ngx_pcalloc( r->pool, sizeof(ngx_http_chunked_filter_ctx_t) );if( ctx == NULL ) {return NGX_ERROR;}ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module);} else {r->keepalive = 0;}}}return ngx_http_next_header_filter(r);
}
2). filter链表的顺序
前面提到了,通过指针将filter模块串联成链表,那么链表中各个模块的顺序是怎样决定的呢?
在make编译前执行configure命令时,会生成ngx_module.c文件,该文件中的ngx_modules数组保存了所有的nginx模块,当然也包括filter模块。nginx就是按照ngx_modules数组中成员的顺序来初始化filter模块链表的顺序的。下图为编译后ngx_module.c文件中ngx_modules数组的内容:
ngx_module_t * ngx_modules[] = {&ngx_core_module,&ngx_errlog_module,&ngx_conf_module,&ngx_regex_module,&ngx_events_module,&ngx_event_core_module,&ngx_epoll_module,&ngx_http_module,&ngx_http_core_module,&ngx_http_log_module,&ngx_http_upstream_module,&ngx_http_static_module,&ngx_http_autoindex_module,&ngx_http_index_module,&ngx_http_auth_basic_module,&ngx_http_access_module,&ngx_http_limit_conn_module,&ngx_http_limit_req_module,&ngx_http_geo_module,&ngx_http_map_module,&ngx_http_split_clients_module,&ngx_http_referer_module,&ngx_http_rewrite_module,&ngx_http_proxy_module,&ngx_http_fastcgi_module,&ngx_http_uwsgi_module,&ngx_http_scgi_module,&ngx_http_memcached_module,&ngx_http_empty_gif_module,&ngx_http_browser_module,&ngx_http_upstream_hash_module,&ngx_http_upstream_ip_hash_module,&ngx_http_upstream_least_conn_module,&ngx_http_upstream_keepalive_module,&ngx_http_upstream_zone_module,&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
};
需要注意的是:链表实际的顺序和ngx_modules数组中的顺序是相反的,即ngx_modules数组中靠前的模块,在链表中是靠后(调用处理)的。当然,你也可以在configure命令执行后,make命令执行前,自行修改ngx_modules.c文件的内容,对ngx_modules数组中的成员进行顺序上的调整。
3. 默认filter模块介绍
- ngx_http_not_modified_filter_module
仅对HTTP头部做处理。在返回200成功时,根据请求中If-Modified-Since或者If-Unmodified-Since头部取得浏览器缓存文件的时间,再分析返回用户文件的最后修改事件,以此决定是否直接饭是钢304响应给用户。
- ngx_http_range_body_filter_module
处理请求中的Range信息,根据Range中的要求返回文件的一部分给用户。
- ngx_http_copy_filter_module
仅对HTTP包体做处理。将用户发送的ngx_chain_t结构的HTTP包体复制到新的ngx_chain_t结构中(都是各种指针的复制,不包括实际HTTP响应内容),后续的HTTP过滤模块处理的ngx_chain_t类型的成员都是ngx_http_copy_filter_module模块处理后的变量。
- ngx_http_headers_filter_module
仅对HTTP头部做处理,允许通过修改nginx.conf配置文件,在返回给用户的响应中添加任意的HTTP头部。
- ngx_http_userid_filter_module
仅对HTTP头部做处理。它基于cookie提供了简单的认证管理功能。
- ngx_http_charset_filter_module
可以将文本返回给用户的响应包,按照nginx.conf中的配置重新进行编码,再返回给用户。
- ngx_http_ssi_filter_module
支持SSI(Server Side Include,服务器端嵌入)功能,将文件内容包含到网页中并返回给用户。
- ngx_http_postpone_filter_module
仅对HTTP包体做处理。它仅应用于subrequest产生的子请求。使得多个子请求同时向客户端发送响应时能够有序,所谓的"有序"是指按照构造子请求的顺序发送响应。
- ngx_http_gzip_filter_module
对特定的HTTP响应包体(如网页或者文本文件)进行gzip压缩,再把压缩后的内容返回给用户。
- ngx_http_range_header_filter_module
支持range协议。
- ngx_http_chunked_filter_module
支持chunked编码
- ngx_http_header_filter_module
仅对HTTP头部做处理。该模块会把r->headers_out结构体中的成员序列化为返回给用户的HTTP响应字符流,包括响应行和响应头部,并通过调用ngx_http_write_filter_module模块中的方法直接将HTTP头部发送到客户端。
- ngx_http_write_filter_module
仅对HTTP包体做处理。该模块负责向客户端发送HTTP响应。
---------------------------------------------------------------------------------------------------------------------------------------------
参考:
《深入理解nginx》
转载于:https://my.oschina.net/hncscwc/blog/777205
nginx源码分析——filter模块相关推荐
- nginx源码分析之模块初始化
在nginx启动过程中,模块的初始化是整个启动过程中的重要部分,而且了解了模块初始化的过程对应后面具体分析各个模块会有事半功倍的效果.在我看来,分析源码来了解模块的初始化是最直接不过的了,所以下面主要 ...
- Nginx 源码分析
1.工程 ngx_conf_file.c ngx_connection.c ngx_cycle.c ngx_file.h ngx_module.c ngx_open_file_cache.h ngx_ ...
- Nginx源码分析:epoll事件处理模块概述
nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 事件处理模块概述 Nginx的高效请求的处理依赖于事件管理机制,本次默认的场景是Linux操 ...
- Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 一
搭建nginx服务器时,主要的配置文件 nginx.conf 是部署和维护服务器人员经常要使用到的文件, 里面进行了许多服务器参数的设置.那么nginx 以模块 module为骨架的设计下是如何运用模 ...
- Nginx源码分析:核心数据结构ngx_cycle_t与内存池概述
nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 核心数据结构与内存池概述 在Nginx中的核心数据结构就是ngx_cycle_t结构,在初始 ...
- nginx源码分析(5)——监听socket初始化
在nginx源码分析(4)中,看到了nginx的事件模型,但其中没有介绍监听socket的初始化.而对于web server来说,需要通过监听socket来监听客户端的连接等.本篇将会具体介绍这方面的 ...
- Nginx源码分析:惊群处理与负载均衡
nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> Nginx的惊群处理与负载均衡概述 当Nginx工作在master/worker模式下时,就 ...
- Nginx源码分析:master/worker工作流程概述
nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> Nginx的master与worker工作模式 在生成环境中的Nginx启动模式基本都是以m ...
- Nginx源码分析:启动流程
nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> nginx简介 Nginx的作为服务端软件,表现的主要特点是更快.高扩展.高可靠性.低内存消 ...
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
最新文章
- 摆脱 FM!这些推荐系统模型真香
- php扩展swoole安装,php 安装swoole扩展
- dfs遍历和bfs遍历python_广度优先遍历(BFS)和深度优先遍历(DFS)
- boost::fusion::result_of::as_map用法的测试程序
- Excel 2013中单元格添加下拉列表的方法
- Python实现中文分词--正向最大匹配和逆向最大匹配
- Google News优化技巧
- Docker hello workd
- 阿里云Ubuntu16.04升级python3.6和pip
- Spring.Web 之双向数据绑定(Bidirectional data binding)
- python3.7怎么安装的_怎么安装python3.7:python 3.7入门教程
- springboot relativepath 不存在_MyBatis初级实战之一:Spring Boot集成
- RHEL6配置yum源为网易镜像
- 思考Hadoop权威指南的一段话
- LEGION联想Y7000P Ubuntu18.04的无线网卡驱动安装
- 虚拟机centos7无法正常启动
- 关于Opencv出现的错误“ 0x000007fefdf6a06d (KernelBase.dll) Microsoft C++ 异常的几种尝试解决方式
- R语言多层桑基图_R语言可视化(二十三):桑基图绘制
- 职场中典型的学生思维有哪些?
- Linux管理员易犯的错误
热门文章
- 鸟哥的Linux私房菜第零章
- mobiscroll手机端插件 好用(时间、日历、颜色)
- 生产者消费者线程在QueueT中实现多线程同步
- pytorch使用说明2
- Navicat操作SQL server 2008R2文件.bak文件还原
- 通过 微软 pai-fs 上传数据到HDFS (Microsoft OpenPAI)
- BZOJ:1816 [Cqoi2010]扑克牌 (贪心或二分答案)
- Android使用adb命令查看CPU信息
- Python的程序结构[2] - 类/Class[1] - 基类与继承
- stm32GPIO8种模式