記一次Http的Content-Length問題

對於http的請求返回結果要進行內容的長度校驗主要有兩種方式,二者互斥使用

  1. 客戶端在 http頭 (header) 加Connection:keep-alive時,服務器的response是Transfer-Encoding:chunked的形式,通知頁面數據是否接收完畢,例如長連接或者程序運行中可以動態的輸出內容,例如一些運算比較複雜且需要用戶及時的得到最新結果,那就採用chunked編碼將內容分塊輸出。
  2. 除了如1所述之外的情況一般都是可以獲取到Content-Length的。

在HTTP協議中,Content-Length用於描述HTTP消息實體的傳輸長度the transfer-length of the message-body。在HTTP協議中,消息實體長度和消息實體的傳輸長度是有區別,比如說gzip壓縮下,消息實體長度是壓縮前的長度,消息實體的傳輸長度是gzip壓縮後的長度。

在具體的HTTP交互中,客戶端是如何獲取消息長度的呢,主要基於以下幾個規則:
響應爲1xx,204,304相應或者head請求,則直接忽視掉消息實體內容。
如果有Transfer-Encoding,則優先採用Transfer-Encoding裏面的方法來找到對應的長度。比如說Chunked模式。

“如果head中有Content-Length,那麼這個Content-Length既表示實體長度,又表示傳輸長度。如果實體長度和傳輸長度不相等(比如說設置了Transfer-Encoding),那麼則不能設置Content-Length。如果設置了Transfer-Encoding,那麼Content-Length將被忽視”。這句話翻譯的優點饒,其實關鍵就一點:有了Transfer-Encoding,則不能有Content-Length。

通過服務器關閉連接能確定消息的傳輸長度。(請求端不能通過關閉連接來指明請求消息體的結束,因爲這樣可以讓服務器沒有機會繼續給予響應)。這種情況主要對應爲短連接,即非keep-alive模式。

HTTP1.1必須支持chunk模式。因爲當不確定消息長度的時候,可以通過chunk機制來處理這種情況。

在包含消息內容的header中,如果有content-length字段,那麼該字段對應的值必須完全和消息主題裏面的長度匹配。
“The entity-length of a message is the length of the message-body before any transfer-codings have been applied”
也就是有chunk就不能有content-length 。

其實後面幾條几乎可以忽視,簡單總結後如下:

  • Content-Length如果存在並且有效的話,則必須和消息內容的傳輸長度完全一致。(經過測試,如果過短則會截斷,過長則會導致超時。)
  • 如果存在Transfer-Encoding(重點是chunked),則在header中不能有Content-Length,有也會被忽視。
  • 如果採用短連接,則直接可以通過服務器關閉連接來確定消息的傳輸長度。(這個很容易懂)
    結合HTTP協議其他的特點,比如說Http1.1之前的不支持keep alive。那麼可以得出以下結論:
    • 在Http 1.0及之前版本中,content-length字段可有可無。因爲這之前都不支持長連接.
    • 在http1.1及之後版本。如果是keep alive,則content-length和chunk必然是二選一。若是非keep alive,則和http1.0一樣。content-length可有可無.

綜合之上總結, 我們的問題:
HTTP服務器返回是以HTTP/1.0返回的, 而且標識了Connection: Close頭. 而瀏覽器請求是以HTTP/1.1請求, 並標識了Connection: Keep-Alive請求的, 所以瀏覽器期望收到至少帶有Transfer-Encoding(重點是chunked)或者Content-Length其中一種方式的頭. 而我們的代理直接發送HTTP響應應該就有問題:

嘗試解決辦法:

  1. hmconfig解析HTTP, 收到的HTTP響應如果帶有Connection: Close的數據發送完成後, 關閉對瀏覽器的連接.
  2. 設備端解析HTTP, 對沒有content-length的HTTP響應補充頭.

以上爲轉載的內容,下面我遇到的問題

問題:
在使用Netty的時候,調用請求默認使用的長連接,並且帶有Content-length信息 ,所以當length過長的時候,會產生超時的問題。

個人解決方法:
刪除Content-Length 請求頭信息,那麼 Netty則會使用transfer-encoding: chunked 屬性,
chunked 爲分塊輸出,就是把「報文」分割成若干個大小已知的塊,塊之間是緊挨着發送的,這樣就不需要在發送之前知道整個報文的大小了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章