<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    聶永的博客

    記錄工作/學習的點點滴滴。

    HTTP/2筆記之消息交換

    前言

    無論是HTTP/1.*還是HTTP/2,HTTP的基本語義是不變的,比如方法語義(GET/PUST/PUT/DELETE),狀態碼(200/404/500等),Range Request,Cacheing,Authentication、URL路徑。以前純文本形式作為傳輸的載體,HTTP/2帶來了與之不同的二進制傳輸語法語義。

    下面為HTTP/2消息交換方便筆記。

    請求/響應流程

    一個典型的HTTP消息包含請求/響應,組成如下:

    • 以響應為例,零或多個HEADERS幀(每一個HEADERS幀可能跟著>=0個CONTINUATION幀,以補充單個HEADERS容量不夠的情況)包含狀態碼為1xx的報文頭響應
    • 或者一個HEADERS幀包含了完整的報文頭(一般情況下)
    • 零個或多個DATA數據幀包含了具體的消息負載內容
    • 一個HEADERS幀,后面跟隨零個或多個包含有報尾(trailer-part)的CONTINUATION幀,作為可選項

    注意事項:

    • 一個HEADERS幀攜帶有END_STREAM標志,后面可跟隨有CONTINUATION幀用以補充剩余的包頭塊
    • 來自于其它流的類型幀是不能夠出現在HEADERS幀和CONTINUATION幀中間
    • DATA數據幀不支持分塊傳輸編碼(chunked transfer encoding)
    • 報尾字段(Trailing header field)當出現在報頭塊中時,可以終止當前流
    • HEADERS幀以及關聯的CONTINUATION幀只能夠出現在一個流的開始或結束時
    • HTTP請求-相應交換消耗一個流:請求準備HEADERS幀打開流,請求的幀包含有END_STREAM標志導致兩端流處于半關閉狀態,half closed(local/server);響應一個HEADERS幀,若某響應幀包含有END_STREAM標志,流將被關閉
    • 一個HTTP響應完成指的響應幀是包含有END_STREAM標志,在服務器發送并且客戶端接收成功。若響應不依賴于客戶端的請求,服務器端可以在先于客戶端發送請求之前發送完成,之后服務器通過再次發送一個RST_STREAM流(錯誤代碼為NO_ERROR)請求客戶端放棄發送請求。這要求客戶端在接收到RST_STREAM幀后必須不能夠丟棄響應,無論是處于什么謹慎原因。

    1. 不支持升級機

    HTTP/2多路復用,以及自身也可以通過HTTP/1.1 101切換古來,因此不支持101切換協議(Switching Protocols)機制也是情理之中。

    2. HTTP Header Fields

    HTTP/2報頭字段注意點:

    1. 和HTTP/1.x報頭字段一樣,都是ASCII字符表示
    2. 字段要求全部小寫,"Accept" -> "accept"
    3. 若大寫,會被作為不完整數據對待,有被丟棄的風險
    4. 新增偽報頭字段,但不屬于常規HTTP頭部字段,不允許終端自己產生,只允許規范中所定義的5個
      • :method
      • :scheme
      • :authority
      • :path
      • :status
    5. 偽報頭字段必須出現在常規HTTP報頭字段之前
    6. 連接屬性專用字段(Connection-Specific Header Fields)不再被使用(但Transfer-Encoding可以允許出現在請求頭中),比如Keep-Alive, Proxy-Connection, Transfer-Encoding和Upgrade等

    3. 簡單示范

    簡單圖片請求:

    模擬一次提交,設置報頭大于16KB(一般情況下,報頭沒有那么大,除非Cookie撐大):

    以上示例,可以幫助理解HTTP/1.x和HTTP/2在HTTP語義表述上的不同。

    4. 可靠性機制

    HTTP/1.1,HTTP客戶端無法重試非冪等請求,尤其在錯誤發生的時候,由于無法檢測錯誤性質這會對重試帶來不利的影響。

    而HTTP/2在這方面有所增強,提供了兩種方式可判斷請求是否被完成:

    • GOAWAY幀會攜帶上流標識符的最大值,低于此值的請求已經被執行過,高于此值的請求幀,則可以再次放心重試
    • 包含有REFUSED_STREAM錯誤代碼的RST_STREAM幀說明當前流早于任何處理發生之前就已經被關閉,因此發生在當前流上的請求可以安全重試。

    另外PING幀有利于客戶端檢測當前連接是否可用,可以理解為心跳保活機制,因為一些網關、負載設備會關閉空閑狀態下的連接以節省資源。

    服務器推送機制

    HTTP/2新增特性,服務器根據客戶端一次請求內容主動推送與之相關的請求過去,避免客戶端在解析出初次請求頁面內容時,再逐一發送資源請求,節省網絡資源利用效率。 一些注意事項:

    • 客戶端可以通過設置SETTINGS_ENABLE_PUSH為0值通知服務器端禁用推送
    • 承諾請求應該是可緩存、安全,并且不能夠攜帶請求的負載內容,這需要客戶端做檢測
    • 推送的響應若不可緩存,客戶端不能作為HTTP cache存儲,這對單獨的非瀏覽器環境特別適合
    • 服務器必須包含一個:authority偽頭部字段,標明自身被授權。客戶端若檢測不到需要作為PROTOCOL_ERROR類型流錯誤對待
    • 中介設備接收到服務器的推送后,可以決定是否要轉發給客戶端,中介可以單獨選擇推送內容發送給客戶端。這是一個特別需要注意的點
    • 客戶端必須拒絕來自服務器端的對SETTINGS_ENABLE_PUSH屬性非0值的修改,也就是說服務器不能要求客戶端打開PUSH開關,客戶端一旦遇到需要響應PROTOCOL_ERROR類型連接錯誤
    • 客戶端不能夠發送推送,PUSH_PROMISE幀只能夠來自于服務器端(作為推送請求者發送),否則將會作為PROTOCOL_ERROR類型的連接錯誤對待
    • PUSH_PROMISE需要包含偽頭部:method,若客戶端認為不安全,必須響應一個PROTOCOL_ERROR類型流錯誤
    • 服務器端應該盡可能早的發送PUSH_PROMISE幀,以避免與來自客戶端對相同資源的請求兩者產生沖突
    • 發送PUSH_PROMISE幀會創建一個新的流,然后處于兩端的保留狀態,reserved (local/remote)
    • 發送完PUSH_PROMISE幀,服務器需要馬上發送具體DATA數據幀
    • 客戶端接收完PUSH_PROMISE幀后,選擇接收PUSH響應內容,這期間不能觸發請求承諾的響應內容,直到承諾流關閉
    • 客戶端不需要接收推送內容時,可以選擇發送RST_STREAM幀,包含CANCEL/REFUSED_STREAM代碼,以及PUSH流標識符發送給服務器端,重置推送流
    • 客戶端可以通過設置SETTINGS_MAX_CONCURRENT_STREAMS限制響應數,值為0禁用。但不能阻止服務器發送PUSH_PROMISE幀

    比如,服務器接收到來自客戶端的請求某個HTML文檔資源,該文檔包含了若干圖片連接,服務器應該優先發送圖片數據到客戶端,這需要優先發送推送承諾早于包含完整HTML文檔內容的DATA幀,這樣客戶端優先接收到承諾資源,后面接收到DATA數據幀進行解析出圖片連接的時候,就避免再次發送圖片資源請求嘛。

    CONNECT方法

    在HTTP原始語義中是沒有CONNECT方法的,這個偽方法(pseudo-method)在HTTP/1.x,HTTP代理用作轉換HTTP連接通過隧洞方式到遠程主機,HTTPS方式交互。 HTTP/2與之類似,偽方法CONNECT被HTTP代理用作在一個單獨的HTTP/2流之上建立一個到遠程主機的隧道,要求如下:

    • :method=CONNECT
    • ":scheme"和":path"被省略
    • ":authority"字段為代理要連接的遠程主機和端口信息

    一旦不滿足要求,會被視為不完整的需求。

    • 連接成功建立,代理發送給客戶端一個2xx的狀態碼
    • 代理兩端在HEADERS幀都發送完畢后,后續的DATA幀開始發送
    • 代理轉發客戶端發送的DATA數據幀到遠程服務器
    • 代理接收到服務器數據組裝成DATA數據幀
    • 非DATA類型數據幀,包括流管理類型的RST_STREAM、WINDOW_UPDATE、PRIORITY幀都是不能夠在已經連接的流上發送的,否則會被當做流錯誤對待
    • 客戶端接收到包含有END_STREAM標志位的DATA幀時,盡量也要發送一個包含有END_STREAM標志位的DATA幀
    • DATA幀END_STREAM標志位被當做TCP FIN比特標志對待:
      • 代理接收到DATA幀帶有END_STREAM標志位,在轉發時會設置TCP FIN比特位
      • 代理接收到TCP段包含有FIN比特位設置時,會轉發一個DATA幀并攜帶END_STREAM標志位
      • 最后的TCP段或DATA幀可以為空
    • TCP連接錯誤以RST_STREAM幀關聯
    • 代理對待在TCP連接中出現的錯誤,包括接收到一個包含有RST比特位的TCP段,作為CONNECT_ERROR類型的流錯誤拋出
    • 一旦檢測到流或HTTP/2連接的錯誤,代理必須發送一個TCP段并且其RST標志被設置
    • 代理不能僅僅依靠SETTINGS_MAX_CONCURRENT_STREAMS屬性值進行限制資源消耗

    持久連接和重用

    HTTP/2消息交換通過持久連接、重用實現,目的盡可能做到資源利用率最大化。

    1. HTTP/2為持久性連接,基于性能原因,規范建議客戶端不要關閉已有連接除非不再需要和服務器保持通信。服務器端要是主動關閉連接的話,在請求量大的情況下,會導致系統出現大量的TIME_WAIT狀態TCP,每一個TIME_WAIT狀態默認情況下至少持續60秒,特別占用系統資源。因此最佳實踐是客戶端主動關閉連接,避免Linux服務器端出現TIME_WAIT。
    2. 基于具體主機和端口,客戶端應該只打開一個HTTP/2連接
    3. 客戶端可以額外創建連接作為替代補充:替換已耗盡可用流標識符,或刷新TLS連接,或替換遇到錯誤的連接
    4. 當任一端想關閉連接的時候,都應該第一時間發送一個GOAWAY幀到對端,告知對方先前發送的幀已經被處理過,終止之后的一些剩余任務,終止可放心關閉
    5. 有一些情況服務器若不希望客戶端重用連接,可返回421 (Misdirected Request) 狀態碼作為響應,默認可緩存(POST方法或cache-control可控制),但代理不能夠為客戶端請求生成421狀態碼。
    6. HTTP代理與每一個服務器之間可以盡可能保持一個持久的連接方便專遞客戶端的請求;客戶端到代理之間可以所有請求共享、重用一個連接

    小結

    以上為HTTP/2消息交換機制的一些簡單梳理,需要注意點:

    1. HTTP/2不允許使用連接特定頭部字段
    2. 新增的5個頭部
    3. 推送機制的一些特性需求
    4. RST_STREAM等幀標志位的使用

    posted on 2015-03-23 16:45 nieyong 閱讀(9405) 評論(0)  編輯  收藏 所屬分類: HTTP

    公告

    所有文章皆為原創,若轉載請標明出處,謝謝~

    新浪微博,歡迎關注:

    導航

    <2015年3月>
    22232425262728
    1234567
    891011121314
    15161718192021
    22232425262728
    2930311234

    統計

    常用鏈接

    留言簿(58)

    隨筆分類(130)

    隨筆檔案(151)

    個人收藏

    最新隨筆

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 久久久久久久尹人综合网亚洲| 亚洲精品无码mⅴ在线观看| 国产亚洲漂亮白嫩美女在线 | 国产日韩一区二区三免费高清| 亚洲国产精品成人网址天堂| www视频在线观看免费| 亚洲AV美女一区二区三区| 最近2019中文免费字幕在线观看| 国产亚洲色婷婷久久99精品| 99精品视频免费| 久热综合在线亚洲精品| 色欲色香天天天综合网站免费| 亚洲高清视频免费| caoporn国产精品免费| 成人毛片免费播放| 久久精品亚洲日本波多野结衣| 98精品全国免费观看视频| 亚洲?V无码成人精品区日韩| 日韩亚洲国产高清免费视频| 永久免费视频v片www| 九九免费精品视频在这里| 亚洲国产精品久久久天堂| 国产92成人精品视频免费| 亚洲乱码无人区卡1卡2卡3| 免费在线观看一级毛片| 最近免费中文字幕MV在线视频3| 亚洲国产美女福利直播秀一区二区| 午夜视频免费成人| 和老外3p爽粗大免费视频| 亚洲美女视频免费| 免费一级毛片女人图片| 久久99免费视频| 亚洲精华液一二三产区| 狠狠亚洲婷婷综合色香五月排名| 国产激情免费视频在线观看| 亚洲一日韩欧美中文字幕在线| 亚洲乱亚洲乱少妇无码| 日本免费网站视频www区| 深夜福利在线免费观看| 亚洲黄色一级毛片| 亚洲成A人片77777国产|