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》