HTTPS
1.二进制分帧层
在HTTP/2中,在应用层和传输层(TCP或者UDP)之间加了一层:二进制分帧层。这是HTTP2中最大的改变。HTTP2之所以性能会比HTTP1.1有那么大的提高,很大程度上正是由于这一层的引入。
在二进制的分帧结构中,头部有8个字节(64bit),其中有一个字节来表示帧类型(帧类型在下面第8点那里会有详细说明)。同时,这些首部与数据体在传输的时候都会经过HPACK压缩(首部压缩算法)。
2.多路复用
- http/1.1:http的管线化可以克服同域的并行请求限制带来的阻塞,但是它是建立在持久连接上的,及时发送完所有数据,服务器也是需要一一响应,如果上一个响应没收到,后面的响应就会进入阻塞还是存在这阻塞的问题。
- https:https是基于二进制数据帧的传输、消息、流(详看第9点),是可以进行乱序的传输,多路复用对同一域名下所有请求都是基于流,所以不存在同域并行的阻塞。
多路复用代替原来的序列和阻塞机制。所有就是请求的都是通过一个 TCP 连接并发完成。因为http/1.1的传输是基于基础文本的(文本分割的解析协议),在多复用中是基于二进制数据帧的传输、消息、流,所以可以做到乱序的传输。多路复用对同一域名下所有请求都是基于流,所以不存在同域并行的阻塞。多次请求如下图:
3.服务端推送 server push
上图中服务器推送的资源可以由不同页面共享,服务器可以按优先级推送资源。
潜在问题:对于服务端来说,只要满足推送条件他就会发起server-push进行推送。但是当客户端先前已经有过该缓存那么他就会发起RST进行拒收,然而这个时候服务器已经把相关资源推送出去。这就造成了无效推送,会占用服务器的带宽,当需要大量推送的时候可能会出现影响用户的后续访问体验。
后续:选择性推送。
4.header 压缩(HPACK)
使用HPACK算法。
4.1 静态索引
HPACK有一个静态索引(静态表),包含了61个常见的HTTP首部名称,如下图所示:
这个表被请求和响应同时享用,HTTP消息可以通过他来压缩常用的首部名,和一些常用的首部名字、首部组合,比如:
首部 :method: DELETE 可以使用索引2或者索引3(2和3都是指向 :method),然后编码DELETE字符串。对于这种情况,在HPACK中是没有明确的说明需要用哪个索引。对此类似的还有 :path、 :status ,发送方可以选择随便的一个索引,甚至可以选择不用然后自己创建一个新的首部名索引。参考Chrome浏览器对 :path 的处理。
4.2 动态索引
除了静态索引(静态表)外HPACK还有一个连接级的动态表,从位置62开始,也就是跟在静态表之后,默认是4096个8位字节,当达到使用满时后续的会占用前面最老的记录。同时在HPACK协议中允许编码器用于动态表的最大大小由SETTINGS_HEADER_TABLE_SIZE
设置确定。
动态表可以包含重复的条目,但是首次使用的时候会导致首部的压缩率降低(规范并没有强制要求发送方发送一定使用动态表)。
5.应用层的重置连接
HTTP/1:设置tcp-segment里的reset-flag来通知关闭连接,会直接断开。
HTTP/2:引入RST_STREAM类型的frame,在不断开连接的前提下取消某个request的stream,表现更好。
tip:RST_STREAM,一种帧格式含标识错误代码的单个无符号的32位整数,错误代码指示流被终止的原因。
6.请求优先级设置
流的一个重要特性是可以设置优先级和资源数据的依赖关系。HTTP/2的每个stream都可以设置依赖和权重,可以按依赖书分配优先级,解决了关键请求被阻塞的问题。
7.流量控制
木桶原理:每个 http2 流都拥有自己的公示的流量窗口,可以限制另一端发送数据。每个流都要让对方知道自己还有足够的空间,并且在背扩大前只允许发送这么多数据。
需要注意的是流量控制说的不是端到端的整个路径,我们访问一个网站需要经过一系列的转发,而流量控制说的就是这一系列转发中的每一次转发的双方也就是单跳的端点之间。
流量控制是基于WINDOW_UPDATE帧然后由接收者全面控制,这就意味着流量控制是有方向的,有大小的(初始值为65535字节)。所以作为接收方时,客户方、服务端、中间代理这些都需要独立公布自身的流量控制窗口,而发送方都要遵守这个流量控制规则。
8.帧
Length:frame的长度,24位无符号数
Type:定义frame的类型为8bits,决定了帧主体的格式和语义,当为unknown的时候应该忽略/抛弃。
Flags:帧类型相关预留的布尔标识。
R:保留比特位。
Stream Identifier用作流控制,31位无符号数。客户端建立的 sid 必须为奇数,服务端建立的 sid 必须为偶数,值 (0x0) 保留给与整个连接相关联的帧 (连接控制消息),而不是单个流。
sid(Security Identifiers):本次会话id,唯一标识符。相当于SESSION ID
Frame Payload是主体内容,由帧类型决定。
十种帧:
-
HEADERS
: 报头帧 (type=0x1),用来打开一个流或者携带一个首部块片段 -
DATA
: 数据帧 (type=0x0),装填主体信息,可以用一个或多个 DATA 帧来返回一个请求的响应主体 -
PRIORITY
: 优先级帧 (type=0x2),指定发送者建议的流优先级,可以在任何流状态下发送 PRIORITY 帧,包括空闲 (idle) 和关闭 (closed) 的流 -
RST_STREAM
: 流终止帧 (type=0x3),用来请求取消一个流,或者表示发生了一个错误,payload 带有一个 32 位无符号整数的错误码 (Error Codes),不能在处于空闲 (idle) 状态的流上发送 RST_STREAM 帧 -
SETTINGS
: 设置帧 (type=0x4),设置此连接
的参数,作用于整个连接 -
PUSH_PROMISE
: 推送帧 (type=0x5),服务端推送,客户端可以返回一个 RST_STREAM 帧来选择拒绝推送的流 -
PING
: PING 帧 (type=0x6),判断一个空闲的连接是否仍然可用,也可以测量最小往返时间 (RTT) -
GOAWAY
: GOWAY 帧 (type=0x7),用于发起关闭连接的请求,或者警示严重错误。GOAWAY 会停止接收新流,并且关闭连接前会处理完先前建立的流 -
WINDOW_UPDATE
: 窗口更新帧 (type=0x8),用于执行流量控制功能,可以作用在单独某个流上 (指定具体 Stream Identifier) 也可以作用整个连接 (Stream Identifier 为 0x0),只有 DATA 帧受流量控制影响。初始化流量窗口后,发送多少负载,流量窗口就减少多少,如果流量窗口不足就无法发送,WINDOW_UPDATE 帧可以增加流量窗口大小 -
CONTINUATION
: 延续帧 (type=0x9),用于继续传送首部块片段序列,见 [首部的压缩与解压缩]
9.流–Stream
9.1reserved
9.2 open
上图是预约状态下的情况,当处于open的流可以被两个对端发送任何类型的帧。
9.3 half-close
- 任一端都可以发送带有 END_STREAM 标识的帧,发送方会转入
half-closed(local)
状态;接收方会转入half-closed(remote)
状态 - 任一端都可以发送 RST_STREAM 帧,这会使流立即进入
closed
状态
流是双向的,半关闭表示流单向关闭了