nginx核心本身不會主動讀取請求體,這個工作是交給請求處理階段的模塊來做,但是nginx核心提供了ngx_http_read_client_request_body()接口來讀取請求體,另外還提供了一個丟棄請求體的接口-ngx_http_discard_request_body(),在請求執行的各個階段中,任何一個階段的模塊如果對請求體感興趣或者希望丟掉客戶端發過來的請求體,可以分別調用這兩個接口來完成。這兩個接口是nginx核心提供的處理請求體的標準接口,如果希望配置文件中一些請求體相關的指令(比如client_body_in_file_only,client_body_buffer_size等)能夠預期工作,以及能夠正常使用nginx內置的一些和請求體相關的變量(比如$request_body和$request_body_file),一般來說所有模塊都必須調用這些接口來完成相應操作,如果需要自定義接口來處理請求體,也應盡量兼容nginx默認的行為。
1,讀取請求體
請求體的讀取一般發生在nginx的content handler中,一些nginx內置的模塊,比如proxy模塊,fastcgi模塊,uwsgi模塊等,這些模塊的行為必須將客戶端過來的請求體(如果有的話)以相應協議完整的轉發到后端服務進程,所有的這些模塊都是調用了ngx_http_read_client_request_body()接口來完成請求體讀取。值得注意的是這些模塊會把客戶端的請求體完整的讀取后才開始往后端轉發數據。
由于內存的限制,ngx_http_read_client_request_body()接口讀取的請求體會部分或者全部寫入一個臨時文件中,根據請求體的大小以及相關的指令配置,請求體可能完整放置在一塊連續內存中,也可能分別放置在兩塊不同內存中,還可能全部存在一個臨時文件中,最后還可能一部分在內存,剩余部分在臨時文件中。下面先介紹一下和這些不同存儲行為相關的指令:
client_body_buffer_size:設置緩存請求體的buffer大小,默認為系統頁大小的2倍,當請求體的大小超過此大小時,nginx會把請求體寫入到臨時文件中??梢愿鶕I務需求設置合適的大小,盡量避免磁盤io操作;
client_body_in_single_buffer:指示是否將請求體完整的存儲在一塊連續的內存中,默認為off,如果此指令被設置為on,則nginx會保證請求體在不大于client_body_buffer_size設置的值時,被存放在一塊連續的內存中,但超過大小時會被整個寫入一個臨時文件;
client_body_in_file_only:設置是否總是將請求體保存在臨時文件中,默認為off,當此指定被設置為on時,即使客戶端顯示指示了請求體長度為0時,nginx還是會為請求創建一個臨時文件。
接著介紹ngx_http_read_client_request_body()接口的實現,它的定義如下:
ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler)
該接口有2個參數,第1個為指向請求結構的指針,第2個為一個函數指針,當請求體讀完時,它會被調用。之前也說到根據nginx現有行為,模塊邏輯會在請求體讀完后執行,這個回調函數一般就是模塊的邏輯處理函數。ngx_http_read_client_request_body()函數首先將參數r對應的主請求的引用加1,這樣做的目的和該接口被調用的上下文有關,一般而言,模塊是在content handler中調用此接口,一個典型的調用如下:
新聞熱點
疑難解答