fzdwx

fzdwx

Hello , https://github.com/fzdwx

HTTP協議

HTTP 1.1 之前的實現就不討論了,因為它們已經過時太久了,我上網的時候就已經接觸不到了,所以主要說說 HTTP/1.1、HTTP/2.

HTTP/1.1#

HTTP/1.1 協議報文簡介#

CRLF: \r\n

METHOD: HTTP 請求,GETPOSTPUTDELETE...

URI: 統一資源標識符,例如/,/index.html...

HTTPVersion: HTTP 協議的版本號,例如HTTP/1.1,HTTP/2

HEADERS: 請求頭,例如Host:localhost,Accept: */*.

BODY: 請求體,例如說一個 JSON 數據{"name":"fzdwx"}

HTTPStatus: HTTP 響應狀態,常見的有200,404

HTTPStatusDesc: HTTP 響應狀態描述,200對應的OK.

請求#

METHOD<SPACE>URI<SPACE>HTTPVersion
HEADERS
<CRLF>
BODY

示例:

GET /hello HTTP/1.1
Host: 192.168.1.107:8889
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

響應#

HTTPVersion HTTPStatus HTTPStatusDesc
HEADERS
<CRLF>
BODY

示例:

如果響應中使用了transfer-encoding: chunked這個來替代Content-Length
, 就表示這是一個不固定大小的響應,結尾通常用0\r\n來分割.

HTTP/1.1 200 OK
transfer-encoding: chunked
content-type: application/json; charset=utf-8

0/r/n

HTTP/1.1 主要新特性#

  1. 默認是長連接 (Connection: Keep-alive), 支持一個 TCP 連接處理多個請求.
  2. 快取策略,在請求頭中使用Cache-Control,Expires,Last-Modified,ETag等來控制.
  3. 允許響應分塊,就是上面提到的transfer-encoding: chunked, 允許服務端可以多次返回響應體.

但是還是存在一定的問題,例如說如果有一個 TCP 連接阻塞了,還是會開啟新的 TCP 連接進行處理請求.

H2#

HTTP2 中的主要概念:

  1. Connection: 一個 TCP 連接包含一個或多個Stream, 所有的通訊都在一個 TCP 連接上完成.
  2. Stream: 一個可以雙向通訊的數據流,包含一條或多條Message, 每個數據流都一個唯一標識符以及可選的優先級信息.
  3. Message: 對應 HTTP/1.1 中的請求或響應,包含一條或多條Frame.
  4. Frame: 最小傳輸單位, 它以二進制進行編碼.

HTTP 通訊簡圖

在 HTTP/1.1 中是有Start Line + header + body 組成的,而在 H2 中是由一個HEADER Frame以及多個DATA Frame組成的.

Frame#

通常有一些公共的字段,例如Length,Type,Flags以及Stream Id;也各個類型所獨有的字段.

分類如下:

  • DATA: 用於傳輸 http 消息體.
  • HEADERS: 用於傳輸首部字段.
  • PRIORITY: 用於指定或重新指定引用資源的優先級.
  • RST_STREAM: 用於通知流的非正常終止.
  • SETTINGS: 用於約定客戶端和服務端的配置數據。例如設置初識的雙向流量控制窗口大小.
  • PUSH_PROMISE: 服務端推送許可.
  • PING: 用於計算往返時間,執行 “活性” 檢活.
  • GOAWAY: 用於通知對端停止在當前連接中創建流.
  • WINDOW_UPDATE: 用於調整個別流或個別連接的流量.
  • CONTINUATION: 專門用於傳遞較大 HTTP 頭部時的持續幀.

為什麼 H2 必須要走 HTTPS?#

這其實在 H2 標準中沒有規定,主要是為了更方便的進行 HTTP 協議的 升級 / 協商,確認一個 Web 服務器是否支持 H2 通常有兩種方式:

  1. 在請求頭中設置Upgrade: HTTP/2.0以及Connection: Upgrade,HTTP2-Settings等,類似升級到Websocket.
  2. 使用TLS中的ALPN(Application Layer Protocol Negotiation, 應用層協議協商) 中的ALPN Next Protocol
    字段,在Client HelloServer Hello這個階段就可以確定下來.

而現在的瀏覽器基本都是實現的方式二, 即與 HTTPS 綁定在一起. 但是如果我們不用瀏覽器進行訪問,當然也可以不用 HTTPS.

詳細可參考.

為什麼 H2 能實現並行響應請求?#

在 HTTP/1.1 中,請求與響應是一一對應的,在同一個連接裡,客戶端依次發送兩個請求,一段時間以後收到來自服務器的一個響應,這個響應一定是對應於第一個發出去的請求的.
因為沒有一個標誌來表示哪個響應對應哪個請求.

而在 H2 中基於StreamFrame的設計: 每個Frame都帶有Stream Id來標識是否為同一個Stream裡面的數據, 每個Stream
互不影響,這樣就能做到在一個 TCP 裡面連接裡傳輸多對請求 / 響應.

H2 的新特性#

H2 的對 HTTP/1.1 優化的核心就是 使用盡可能少的連接數.

  1. 多路復用:只用一個 TCP 連接就能處理多對 請求 / 響應,不用在開啟另外的 TCP 連接,就是通過StreamFrame來實現的.
  2. 二進制分幀:使用Frame為最小單位進行通訊,並採用二進制編碼.
  3. 頭部壓縮: 使用HPACK算法進行優化.
    • 維護一份相同的靜態字典, 包含常見的請求頭的 KV 組合
    • 一份動態字典,可以動態的擴容 (每個連接單獨維護)
    • 支持哈夫曼編碼 (靜態哈夫曼碼表)

    在 HTTP/1 中消息體可以用 gzip 進行壓縮,但是請求頭通常沒有任何壓縮,有時候請求頭的數據可能比請求體的數據還多.

  4. 請求優先級:一般在HEADERS幀與PRIORITY幀中攜帶,通常依賴於服務端的支持程度.

工具#

生成測試簽名#

go run $GOROOT/src/crypto/tls/generate_cert.go --host localhost

使用 curl 調試 HTTPS#

curl https://zcygov.cn -vv
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。