Go猜想录
大道至简,悟者天成
http2 包演进历史

HTTP 协议历史

HTTP/0.9 (1991)

有 get,post 等方法了

GET /\r\n
<HTML>
<HEAD><TITLE>...</TITLE></HEAD>
<BODY>
…
</BODY></HTML>
(disconnect)

HTTP/1.0 (1996)

新增了协议号,Headers,Content-Type

GET / HTTP/1.0\r\n
User-Agent: Mozilla/3.0 (X11; blah)\r\n
Cookie: foo=val\r\n
\r\n
HTTP/1.0 200 OK
Content-Type: text/html

<HTML>...
(disconnect)

HTTP/1.0, evolved

新增 Connection Header,设置为 keep-alive 后续的请求可以使用同一个 tcp 连接

GET / HTTP/1.1\r\n
User-Agent: Mozilla/3.0 (X11; blah)\r\n
Connection: keep-alive\r\n
\r\n
HTTP/1.0 200 OK
Content-Length: 1203
Content-Type: text/html
Connection: keep-alive

<HTML>...
GET /underconstruction.gif HTTP/1.1\r\n  ...

HTTP/1.1 (~1999)

  • keep-alive 改为默认设置,发送 Connection: close 才会断开连接
  • 支持 Transfer-Encoding: chunked,可以发送位置大小的数据,不需要关闭 tcp 连接来通知发送结束了
GET / HTTP/1.1\r\n
User-Agent: Mozilla/3.0 (X11; blah)\r\n
Host: example.com\r\n
\r\n
HTTP/1.1 200 OK
Content-Type: text/html
Transfer-Encoding: chunked

3FF
<HTML>...
GET /underconstruction.gif HTTP/1.1\r\n ...

实操

$ telnet example.com 80
Trying 93.184.215.14...
Connected to example.com.
Escape character is '^]'.
GET / HTTP/1.1
Host: example.com

HTTP/1.1 200 OK
Accept-Ranges: bytes
Age: 402131
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
...

HTTP/1. x 的问题

  • One thing at a time
  • Lots of waiting
  • TCP setup, slow start
  • TLS handshakes too: ClientHello, ServerHello
  • requests are ~800B+cookies
  • No way for servers to gracefully shut down
    • Server TCP FIN & client request both in flight
  • No way for client to abort a request without killing TCP connection
  • Workaround, special cases
http1

HTTP/2 (2012-)

http2 的诞生用于修复 http1.x 中存在的诸多问题,如队头阻塞、头部冗余、连接复用等问题

  • 语义和 http1.x 保持一致
  • 二进制协议
  • 支持多路复用
  • 头部压缩
  • 请求优先级
  • 服务器推送

基本概念

  • 流:流是连接中的一个虚拟信道,可以承载双向的消息
  • 消息:是指逻辑上的 HTTP 消息,比如请求、响应等
  • 帧:HTTP 2.0 通信的最小单位,每个帧包含帧首部,至少也会标识出当前帧所属的流,承载着特定类型的数据

image.png

使用帧作为数据传输的单位

  • 9 个字节的头帧数据
    • 3 个字节的帧长度
    • 1 个字节的帧类型
    • 1 个字节的 flags 数据
    • 4 个字节的 Stream ID
  • N 个字节的 payload
0x00000c010500000001828466882f91d35d055c87a7

image.png

目前有 9 种基础帧类型

const (
	FrameData         FrameType = 0x0
	FrameHeaders      FrameType = 0x1
	FramePriority     FrameType = 0x2
	FrameRSTStream    FrameType = 0x3
	FrameSettings     FrameType = 0x4
	FramePushPromise  FrameType = 0x5
	FramePing         FrameType = 0x6
	FrameGoAway       FrameType = 0x7
	FrameWindowUpdate FrameType = 0x8
	FrameContinuation FrameType = 0x9
)

多路复用

http2 链路是全双工的且支持多路复用,多个流的数据的可以交替传输

http2-conn.png

HPACK 算法

HPACK 是 HTTP/2 中的头部压缩格式,主要用于减少头部数据的大小,从而提高传输效率。

如下图所示,已有的 header 就不会再重复发送。

image.png

协议磋商

  • 询问服务器是否支持 http 2 不支持则降级为 http 1.1
    • 发起带有 HTTP 2.0 Upgrade 首部的 HTTP 1.1 请求
    • 服务器拒绝升级,通过 HTTP 1.1 返回响应
    • 服务器接受 HTTP 2.0 升级,切换到新分帧

image.png image.png

请求流程

image.png

HTTPS 请求流程

image.png

延伸阅读


知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。