<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                這節我們講request,在nginx中我們指的是http請求,具體到nginx中的數據結構是ngx_http_request_t。ngx_http_request_t是對一個http請求的封裝。 我們知道,一個http請求,包含請求行、請求頭、請求體、響應行、響應頭、響應體。 http請求是典型的請求-響應類型的的網絡協議,而http是文件協議,所以我們在分析請求行與請求頭,以及輸出響應行與響應頭,往往是一行一行的進行處理。如果我們自己來寫一個http服務器,通常在一個連接建立好后,客戶端會發送請求過來。然后我們讀取一行數據,分析出請求行中包含的method、uri、http_version信息。然后再一行一行處理請求頭,并根據請求method與請求頭的信息來決定是否有請求體以及請求體的長度,然后再去讀取請求體。得到請求后,我們處理請求產生需要輸出的數據,然后再生成響應行,響應頭以及響應體。在將響應發送給客戶端之后,一個完整的請求就處理完了。當然這是最簡單的webserver的處理方式,其實nginx也是這樣做的,只是有一些小小的區別,比如,當請求頭讀取完成后,就開始進行請求的處理了。nginx通過ngx_http_request_t來保存解析請求與輸出響應相關的數據。 那接下來,簡要講講nginx是如何處理一個完整的請求的。對于nginx來說,一個請求是從ngx_http_init_request開始的,在這個函數中,會設置讀事件為ngx_http_process_request_line,也就是說,接下來的網絡事件,會由ngx_http_process_request_line來執行。從ngx_http_process_request_line的函數名,我們可以看到,這就是來處理請求行的,正好與之前講的,處理請求的第一件事就是處理請求行是一致的。通過ngx_http_read_request_header來讀取請求數據。然后調用ngx_http_parse_request_line函數來解析請求行。nginx為提高效率,采用狀態機來解析請求行,而且在進行method的比較時,沒有直接使用字符串比較,而是將四個字符轉換成一個整型,然后一次比較以減少cpu的指令數,這個前面有說過。很多人可能很清楚一個請求行包含請求的方法,uri,版本,卻不知道其實在請求行中,也是可以包含有host的。比如一個請求GET?[http://www.taobao.com/uri](http://www.taobao.com/uri)HTTP/1.0這樣一個請求行也是合法的,而且host是www.taobao.com,這個時候,nginx會忽略請求頭中的host域,而以請求行中的這個為準來查找虛擬主機。另外,對于對于http0.9版來說,是不支持請求頭的,所以這里也是要特別的處理。所以,在后面解析請求頭時,協議版本都是1.0或1.1。整個請求行解析到的參數,會保存到ngx_http_request_t結構當中。 在解析完請求行后,nginx會設置讀事件的handler為ngx_http_process_request_headers,然后后續的請求就在ngx_http_process_request_headers中進行讀取與解析。ngx_http_process_request_headers函數用來讀取請求頭,跟請求行一樣,還是調用ngx_http_read_request_header來讀取請求頭,調用ngx_http_parse_header_line來解析一行請求頭,解析到的請求頭會保存到ngx_http_request_t的域headers_in中,headers_in是一個鏈表結構,保存所有的請求頭。而HTTP中有些請求是需要特別處理的,這些請求頭與請求處理函數存放在一個映射表里面,即ngx_http_headers_in,在初始化時,會生成一個hash表,當每解析到一個請求頭后,就會先在這個hash表中查找,如果有找到,則調用相應的處理函數來處理這個請求頭。比如:Host頭的處理函數是ngx_http_process_host。 當nginx解析到兩個回車換行符時,就表示請求頭的結束,此時就會調用ngx_http_process_request來處理請求了。ngx_http_process_request會設置當前的連接的讀寫事件處理函數為ngx_http_request_handler,然后再調用ngx_http_handler來真正開始處理一個完整的http請求。這里可能比較奇怪,讀寫事件處理函數都是ngx_http_request_handler,其實在這個函數中,會根據當前事件是讀事件還是寫事件,分別調用ngx_http_request_t中的read_event_handler或者是write_event_handler。由于此時,我們的請求頭已經讀取完成了,之前有說過,nginx的做法是先不讀取請求body,所以這里面我們設置read_event_handler為ngx_http_block_reading,即不讀取數據了。剛才說到,真正開始處理數據,是在ngx_http_handler這個函數里面,這個函數會設置write_event_handler為ngx_http_core_run_phases,并執行ngx_http_core_run_phases函數。ngx_http_core_run_phases這個函數將執行多階段請求處理,nginx將一個http請求的處理分為多個階段,那么這個函數就是執行這些階段來產生數據。因為ngx_http_core_run_phases最后會產生數據,所以我們就很容易理解,為什么設置寫事件的處理函數為ngx_http_core_run_phases了。在這里,我簡要說明了一下函數的調用邏輯,我們需要明白最終是調用ngx_http_core_run_phases來處理請求,產生的響應頭會放在ngx_http_request_t的headers_out中,這一部分內容,我會放在請求處理流程里面去講。nginx的各種階段會對請求進行處理,最后會調用filter來過濾數據,對數據進行加工,如truncked傳輸、gzip壓縮等。這里的filter包括header filter與body filter,即對響應頭或響應體進行處理。filter是一個鏈表結構,分別有header filter與body filter,先執行header filter中的所有filter,然后再執行body filter中的所有filter。在header filter中的最后一個filter,即ngx_http_header_filter,這個filter將會遍歷所有的響應頭,最后需要輸出的響應頭在一個連續的內存,然后調用ngx_http_write_filter進行輸出。ngx_http_write_filter是body filter中的最后一個,所以nginx首先的body信息,在經過一系列的body filter之后,最后也會調用ngx_http_write_filter來進行輸出(有圖來說明)。 這里要注意的是,nginx會將整個請求頭都放在一個buffer里面,這個buffer的大小通過配置項client_header_buffer_size來設置,如果用戶的請求頭太大,這個buffer裝不下,那nginx就會重新分配一個新的更大的buffer來裝請求頭,這個大buffer可以通過large_client_header_buffers來設置,這個large_buffer這一組buffer,比如配置4 8k,就是表示有四個8k大小的buffer可以用。注意,為了保存請求行或請求頭的完整性,一個完整的請求行或請求頭,需要放在一個連續的內存里面,所以,一個完整的請求行或請求頭,只會保存在一個buffer里面。這樣,如果請求行大于一個buffer的大小,就會返回414錯誤,如果一個請求頭大小大于一個buffer大小,就會返回400錯誤。在了解了這些參數的值,以及nginx實際的做法之后,在應用場景,我們就需要根據實際的需求來調整這些參數,來優化我們的程序了。 處理流程圖: ![](https://box.kancloud.cn/2015-08-12_55cb06b1960cd.PNG) 以上這些,就是nginx中一個http請求的生命周期了。我們再看看與請求相關的一些概念吧。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看