### nginx的請求處理[](http://tengine.taobao.org/book/chapter_02.html#id12 "永久鏈接至標題")
nginx使用一個多進程模型來對外提供服務,其中一個master進程,多個worker進程。master進程負責管理nginx本身和其他worker進程。
所有實際上的業務處理邏輯都在worker進程。worker進程中有一個函數,執行無限循環,不斷處理收到的來自客戶端的請求,并進行處理,直到整個nginx服務被停止。
worker進程中,ngx_worker_process_cycle()函數就是這個無限循環的處理函數。在這個函數中,一個請求的簡單處理流程如下:
1. 操作系統提供的機制(例如epoll, kqueue等)產生相關的事件。
1. 接收和處理這些事件,如是接受到數據,則產生更高層的request對象。
1. 處理request的header和body。
1. 產生響應,并發送回客戶端。
1. 完成request的處理。
1. 重新初始化定時器及其他事件。
[](http:// "點擊提交Issue,反饋你的意見...")
### 請求的處理流程[](http://tengine.taobao.org/book/chapter_02.html#id13 "永久鏈接至標題")
為了讓大家更好的了解nginx中請求處理過程,我們以HTTP Request為例,來做一下詳細地說明。
從nginx的內部來看,一個HTTP Request的處理過程涉及到以下幾個階段。
1. 初始化HTTP Request(讀取來自客戶端的數據,生成HTTP Request對象,該對象含有該請求所有的信息)。
1. 處理請求頭。
1. 處理請求體。
1. 如果有的話,調用與此請求(URL或者Location)關聯的handler。
1. 依次調用各phase handler進行處理。
在這里,我們需要了解一下phase handler這個概念。phase字面的意思,就是階段。所以phase handlers也就好理解了,就是包含若干個處理階段的一些handler。
在每一個階段,包含有若干個handler,再處理到某個階段的時候,依次調用該階段的handler對HTTP Request進行處理。
通常情況下,一個phase handler對這個request進行處理,并產生一些輸出。通常phase handler是與定義在配置文件中的某個location相關聯的。
一個phase handler通常執行以下幾項任務:
1. 獲取location配置。
1. 產生適當的響應。
1. 發送response header。
1. 發送response body。
當nginx讀取到一個HTTP Request的header的時候,nginx首先查找與這個請求關聯的虛擬主機的配置。如果找到了這個虛擬主機的配置,那么通常情況下,這個HTTP Request將會經過以下幾個階段的處理(phase handlers):
<table class="docutils field-list" frame="void" rules="none" style="margin: 0px -0.5em; border: 0px;"><colgroup><col class="field-name"/><col class="field-body"/></colgroup><tbody valign="top"><tr class="field-odd field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">NGX_HTTP_POST_READ_PHASE:</th></tr><tr class="field-odd field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;">?</td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">讀取請求內容階段</td></tr><tr class="field-even field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">NGX_HTTP_SERVER_REWRITE_PHASE:</th></tr><tr class="field-even field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;">?</td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">Server請求地址重寫階段</td></tr><tr class="field-odd field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">NGX_HTTP_FIND_CONFIG_PHASE:</th></tr><tr class="field-odd field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;">?</td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">配置查找階段:</td></tr><tr class="field-even field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">NGX_HTTP_REWRITE_PHASE:</th></tr><tr class="field-even field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;">?</td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">Location請求地址重寫階段</td></tr><tr class="field-odd field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">NGX_HTTP_POST_REWRITE_PHASE:</th></tr><tr class="field-odd field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;">?</td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">請求地址重寫提交階段</td></tr><tr class="field-even field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">NGX_HTTP_PREACCESS_PHASE:</th></tr><tr class="field-even field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;">?</td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">訪問權限檢查準備階段</td></tr><tr class="field-odd field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">NGX_HTTP_ACCESS_PHASE:</th></tr><tr class="field-odd field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;">?</td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">訪問權限檢查階段</td></tr><tr class="field-even field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">NGX_HTTP_POST_ACCESS_PHASE:</th></tr><tr class="field-even field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;">?</td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">訪問權限檢查提交階段</td></tr><tr class="field-odd field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">NGX_HTTP_TRY_FILES_PHASE:</th></tr><tr class="field-odd field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;">?</td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">配置項try_files處理階段</td></tr><tr class="field-even field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">NGX_HTTP_CONTENT_PHASE:</th></tr><tr class="field-even field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;">?</td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">內容產生階段</td></tr><tr class="field-odd field"><th class="field-name" colspan="2" style="padding: 1px 8px 1px 5px; border: 0px !important;">NGX_HTTP_LOG_PHASE:</th></tr><tr class="field-odd field"><td style="padding: 1px 8px 1px 5px; border: 0px !important;">?</td><td class="field-body" style="padding: 1px 8px 1px 5px; border: 0px !important;">日志模塊處理階段</td></tr></tbody></table>
在內容產生階段,為了給一個request產生正確的響應,nginx必須把這個request交給一個合適的content handler去處理。如果這個request對應的location在配置文件中被明確指定了一個content handler,那么nginx就可以通過對location的匹配,直接找到這個對應的handler,并把這個request交給這個content handler去處理。這樣的配置指令包括像,perl,flv,proxy_pass,mp4等。
如果一個request對應的location并沒有直接有配置的content handler,那么nginx依次嘗試:
1. 如果一個location里面有配置 random_index on,那么隨機選擇一個文件,發送給客戶端。
1. 如果一個location里面有配置 index指令,那么發送index指令指明的文件,給客戶端。
1. 如果一個location里面有配置 autoindex on,那么就發送請求地址對應的服務端路徑下的文件列表給客戶端。
1. 如果這個request對應的location上有設置gzip_static on,那么就查找是否有對應的.gz文件存在,有的話,就發送這個給客戶端(客戶端支持gzip的情況下)。
1. 請求的URI如果對應一個靜態文件,static module就發送靜態文件的內容到客戶端。
內容產生階段完成以后,生成的輸出會被傳遞到filter模塊去進行處理。filter模塊也是與location相關的。所有的fiter模塊都被組織成一條鏈。輸出會依次穿越所有的filter,直到有一個filter模塊的返回值表明已經處理完成。
這里列舉幾個常見的filter模塊,例如:
1. server-side includes。
1. XSLT filtering。
1. 圖像縮放之類的。
1. gzip壓縮。
在所有的filter中,有幾個filter模塊需要關注一下。按照調用的順序依次說明如下:
| write: | 寫輸出到客戶端,實際上是寫到連接對應的socket上。 |
|-----|-----|
| postpone: | 這個filter是負責subrequest的,也就是子請求的。 |
| copy: | 將一些需要復制的buf(文件或者內存)重新復制一份然后交給剩余的body 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 模塊編譯,調試與測試