在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编码形式发送。nginx
经过调用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模块进行处理。cookie
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); }
前面提到了,经过指针将filter模块串联成链表,那么链表中各个模块的顺序是怎样决定的呢?ide
在make编译前执行configure命令时,会生成ngx_module.c文件,该文件中的ngx_modules数组保存了全部的nginx模块,固然也包括filter模块。nginx就是按照ngx_modules数组中成员的顺序来初始化filter模块链表的顺序的。下图为编译后ngx_module.c文件中ngx_modules数组的内容:memcached
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数组中的成员进行顺序上的调整。函数
仅对HTTP头部作处理。在返回200成功时,根据请求中If-Modified-Since或者If-Unmodified-Since头部取得浏览器缓存文件的时间,再分析返回用户文件的最后修改事件,以此决定是否直接饭是钢304响应给用户。post
处理请求中的Range信息,根据Range中的要求返回文件的一部分给用户。
仅对HTTP包体作处理。将用户发送的ngx_chain_t结构的HTTP包体复制到新的ngx_chain_t结构中(都是各类指针的复制,不包括实际HTTP响应内容),后续的HTTP过滤模块处理的ngx_chain_t类型的成员都是ngx_http_copy_filter_module模块处理后的变量。
仅对HTTP头部作处理,容许经过修改nginx.conf配置文件,在返回给用户的响应中添加任意的HTTP头部。
仅对HTTP头部作处理。它基于cookie提供了简单的认证管理功能。
能够将文本返回给用户的响应包,按照nginx.conf中的配置从新进行编码,再返回给用户。
支持SSI(Server Side Include,服务器端嵌入)功能,将文件内容包含到网页中并返回给用户。
仅对HTTP包体作处理。它仅应用于subrequest产生的子请求。使得多个子请求同时向客户端发送响应时可以有序,所谓的"有序"是指按照构造子请求的顺序发送响应。
对特定的HTTP响应包体(如网页或者文本文件)进行gzip压缩,再把压缩后的内容返回给用户。
支持range协议。
支持chunked编码
仅对HTTP头部作处理。该模块会把r->headers_out结构体中的成员序列化为返回给用户的HTTP响应字符流,包括响应行和响应头部,并经过调用ngx_http_write_filter_module模块中的方法直接将HTTP头部发送到客户端。
仅对HTTP包体作处理。该模块负责向客户端发送HTTP响应。
---------------------------------------------------------------------------------------------------------------------------------------------
参考:
《深刻理解nginx》