在CONTENT階段產生的數據被發往客戶端(系統發送緩存區)之前,會先經過過濾。Nginx的filter的工作方式和做魚有些類似。比如一條魚,可以把它切成魚片(也可以切塊,切泥),然后通過不同的烹飪方法就得到水煮魚或者日式生魚片或者廢了等等。同樣是一條魚,加工得到的結果卻截然不同,就是因為中間不同的工序賦予了這條魚各種屬性。Nginx的filter也是一個道理,前面的Handler好比這條魚,filter負責加工,最后得到的HTTP響應就會各種各樣,格式可以是JSON或者YAML,內容可能多一些或者少一些,HTTP屬性可各異,可以選擇壓縮,甚至內容可以被丟棄。
對應HTTP請求的響應頭和響應體,Nginx分別設置了header filter和body filter。兩種機制都是采用鏈表的方式,不同過濾模塊對應鏈表的一個節點,一般而言一個模塊會同時注冊header filter和body filter。一個典型的filter模塊,比如gzip模塊使用類似如下的代碼來注冊:
[](http:// "點擊提交Issue,反饋你的意見...")
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_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_header_filter = ngx_http_gzip_header_filter;
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_gzip_body_filter;
return NGX_OK;
}
上面的代碼中,gzip模塊首先在模塊的開頭聲明了兩個static類型的全局變量ngx_http_next_header_filter和ngx_http_next_body_filter,在ngx_http_gzip_filter_init函數中,這二個變量分別被賦值為ngx_http_top_header_filter及ngx_http_top_body_filter。而后二者定義在ngx_http.c,并在ngx_http.h頭文件中被導出。ngx_http_top_header_filter和ngx_http_top_body_filter實際上是filter鏈表的頭結點,每次注冊一個新的filter模塊時,它們的值先被保存在新模塊的內部全局變量ngx_http_next_header_filter及ngx_http_next_body_filter,然后被賦值為新模塊注冊的filter函數,而且Nginx filter是先從頭節點開始執行,所以越晚注冊的模塊越早執行。
采用默認編譯選項,Nginx默認編譯的模塊如下:
[](http:// "點擊提交Issue,反饋你的意見...")
ngx_module_t *ngx_modules[] = {
&ngx_core_module,
&ngx_errlog_module,
&ngx_conf_module,
&ngx_events_module,
&ngx_event_core_module,
&ngx_epoll_module,
&ngx_regex_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_ip_hash_module,
&ngx_http_upstream_keepalive_module,
&ngx_http_write_filter_module, /* 最后一個body filter,負責往外發送數據 */
&ngx_http_header_filter_module, /* 最后一個header filter,負責在內存中拼接出完整的http響應頭,
并調用ngx_http_write_filter發送 */
&ngx_http_chunked_filter_module, /* 對響應頭中沒有content_length頭的請求,強制短連接(低于http 1.1)
或采用chunked編碼(http 1.1) */
&ngx_http_range_header_filter_module, /* header filter,負責處理range頭 */
&ngx_http_gzip_filter_module, /* 支持流式的數據壓縮 */
&ngx_http_postpone_filter_module, /* body filter,負責處理子請求和主請求數據的輸出順序 */
&ngx_http_ssi_filter_module, /* 支持過濾SSI請求,采用發起子請求的方式,去獲取include進來的文件 */
&ngx_http_charset_filter_module, /* 支持添加charset,也支持將內容從一種字符集轉換到另外一種字符集 */
&ngx_http_userid_filter_module, /* 支持添加統計用的識別用戶的cookie */
&ngx_http_headers_filter_module, /* 支持設置expire和Cache-control頭,支持添加任意名稱的頭 */
&ngx_http_copy_filter_module, /* 根據需求重新復制輸出鏈表中的某些節點
(比如將in_file的節點從文件讀出并復制到新的節點),并交給后續filter
進行處理 */
&ngx_http_range_body_filter_module, /* body filter,支持range功能,如果請求包含range請求,
那就只發送range請求的一段內容 */
&ngx_http_not_modified_filter_module, /* 如果請求的if-modified-since等于回復的last-modified值,
說明回復沒有變化,清空所有回復的內容,返回304 */
NULL
};
從模塊的命名可以很容易看出哪些模塊是filter模塊,一般而言Nginx的filter模塊名以filter_module結尾,普通的模塊名以module結尾。上面的列表從下往上看,ngx_http_not_modified_filter_module實際上filter鏈的第一個節點,而ngx_http_write_filter_module是最后一個節點。filter模塊的執行順序特別重要,比如數據經過gzip模塊后就變成了壓縮之后的數據,如果在gzip模塊后面運行的filter模塊需要再查看數據的原始內容就不可能了(除非再做解壓),第三方模塊會被Nginx注冊在ngx_http_copy_filter_module之后,ngx_http_headers_filter_module之前。這樣設定的原因是為了確保一些模塊比如gzip filter,chunked filter,copy filter運行在filter鏈的開頭或尾部。
- 上篇:nginx模塊開發篇
- nginx平臺初探
- 初探nginx架構
- nginx基礎概念
- connection
- request
- keepalive
- pipe
- lingering_close
- 基本數據結構
- ngx_str_t
- ngx_pool_t
- ngx_array_t
- ngx_hash_t
- ngx_hash_wildcard_t
- ngx_hash_combined_t
- ngx_hash_keys_arrays_t
- ngx_chain_t
- ngx_buf_t
- ngx_list_t
- ngx_queue_t
- nginx的配置系統
- 指令參數
- 指令上下文
- nginx的模塊化體系結構
- 模塊的分類
- nginx的請求處理
- handler模塊
- handler模塊簡介
- 模塊的基本結構
- 模塊配置結構
- 模塊配置指令
- 模塊上下文結構
- 模塊的定義
- handler模塊的基本結構
- handler模塊的掛載
- handler的編寫步驟
- 示例: hello handler 模塊
- handler模塊的編譯和使用
- 更多handler模塊示例分析
- http access module
- http static module
- http log module
- 過濾模塊
- 過濾模塊簡介
- 過濾模塊的分析
- upstream模塊
- upstream模塊
- upstream模塊接口
- memcached模塊分析
- 本節回顧
- 負載均衡模塊
- 配置
- 指令
- 鉤子
- 初始化配置
- 初始化請求
- peer.get和peer.free回調函數
- 本節回顧
- 其他模塊
- core模塊
- event模塊
- 模塊開發高級篇
- 變量
- 下篇:nginx原理解析篇
- nginx架構詳解
- nginx的源碼目錄結構
- nginx的configure原理
- 模塊編譯順序
- nginx基礎設施
- 內存池
- nginx的啟動階段
- 概述
- 共有流程
- 配置解析
- nginx的請求處理階段
- 接收請求流程
- http請求格式簡介
- 請求頭讀取
- 解析請求行
- 解析請求頭
- 請求體讀取
- 讀取請求體
- 丟棄請求體
- 多階段處理請求
- 多階段執行鏈
- POST_READ階段
- SERVER_REWRITE階段
- FIND_CONFIG階段
- REWRITE階段
- POST_REWRITE階段
- PREACCESS階段
- ACCESS階段
- POST_ACCESS階段
- TRY_FILES階段
- CONTENT階段
- LOG階段
- Nginx filter
- header filter分析
- body filter分析
- ngx_http_copy_filter_module分析
- ngx_http_write_filter_module分析
- subrequest原理解析
- https請求處理解析
- 附錄A 編碼風格
- 附錄B 常用API
- 附錄C 模塊編譯,調試與測試