在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》