上篇HTTP1.1结尾中提到,因为需要按照顺序执行,因此如果第一个请求耗时会造成阻塞问题。
09年谷歌公开自研的SPDY协议基于此15年HTTP/2发布。
二进制协议/分帧
HTTP1.1中头信息是文本(ASCII编码),数据体可以是文本也可以是二进制。而HTTP2中从头信息到数据体都是二进制,并且统称为帧,叫头信息帧(Headers frame)和数据帧(Data frame)。
二进制的好处,可以定义额外的帧,为其他功能打好基础,HTTP2定义了近十几种帧。
二进制分帧也是HTTP2.0性能增强的核心。新增了二进制分帧层。在二进制分帧层上,HTTP2.0会将所有传输的信息分割为更小的消息和,并对它们采用二进制格式的编码。帧是数据传输最小单位,以二进制传输代替原来明文传输。
Http2中所有通信在一个TCP连接上(connection)完成,这个连接可以承载一或多个的双向数据流(stream)。每个数据流以消息(message)的形式发送,message是逻辑概念,而消息由1或多个帧(frame)组成,这个帧可以乱序发送,根据每个帧首部的流标识符重新组装。
上面提到的connection、message、stream、frame也是HTTP2重要的4个特性。
Frame
-
Frame Header
-
Length payload长度
-
Type 帧类型(头或数据等)
-
Flags 如果结束END_HEADERS头结束
相当于HTTP1的空行(“\r\n”)
-
R 保留位
-
Stream Identifier 流标识符
流有标识符,帧没有。因此帧不能乱序,流可以乱序。 实现多路复用的关键。接收端的实现可以根据这个ID并发、组装消息一个stream内frame必须是有序的。
-
-
Frame Payload
多工 双向实时通信 Connection
HTTP2中复用TCP连接,但是不需要再按照顺序进行一一对应了,避免了“对头堵塞”。
在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分,接着回应B请求,等B请求完成后,再发送A请求剩下的部分。
那么在同一个连接中,连续的数据包可能属于不同的响应,要怎么标记数据包,指明是哪个回应呢?
数据流 Stream
HTTP/2将每个请求或回应的所有数据包,称为一个数据流 (stream)。每个数据流都有一个独一无二的编号,流标识Stream ID也是支持多路复用的关键。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。在同一个Stream内部的frame由于没有其他的ID编号,所以无法乱序必须有序,这个时候是无法并发的。另外还规定,客户端发出的数据流ID为奇数,服务器发出的ID为偶数。可以承载数十或数百个流复用。
客户端可以指定数据流的优先级。
数据发送到一半时,客户端和服务端都可以发送信号取消这个数据流。HTTP1.1中只能关闭TCP连接,HTTP2中可以保证TCP打开,取消这个请求,还可以被其他请求复用。
头信息压缩
因为http无状态,因此每次请求附带上所有信息。HTTP2中为了进行优化,提出了2方面解决方案:
- 使用gzip或compress压缩后发送
- 客户端和服务端同时维护一张信息表,所有字段都会存入这个表中生成一个索引号,一个索引号对应一个数据字段,以后就不会发送同样字段,只需要发送索引号。
服务器推送
在有连接的前提下,HTTP2可以未经客户端允许,主动向客户端发送资源。推送依赖性请求的关键,客户端发起的流是奇数编号,服务端发起的流是偶数编号。