http2.0介绍
http2.0介绍
背景
几乎所有互联网上的网页内容都采用了http1.1传输。随着网页内容和样式的发展,http1.1协议的劣势逐渐明显并最终拖了后腿。
于是在2014年HTTPbis小组决定定制http2.0协议。而早在2012年google就设计了SPDY协议用来解决http1.1的缺陷,并被用于Google Chrome浏览器中来访问Google的SSL加密服务,据官方说明使用spdy协议页面加载时间相比于http1.x减少了64%。因此,HTTPbis便基于SPDY/3草案进行一些修改之后发布了http2的draft-00。
RFC 7540 (HTTP/2) 和 RFC 7541 (HPACK)
http2.0
简介
-
继续维持HTTP1.1的模型。 客户端基于tcp协议发送请求到服务器。
-
不改变
http://和https://协议的URL。 -
新的二进制格式。
为了解h2协议还需要了解这三个概念:
-
数据流(stream): 已建立的连接内的双向字节流,用唯一ID标示,可以承载一条或多条消息。
-
消息(message): 每条消息都是一条逻辑的HTTP消息(request 或response),包含一个或多个帧。
-
帧(frame): h2通信的最小单位,每个帧都包含帧头。承载着特定类型的数据(http头、payload等)。来至不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识重组。
http2 的帧格式:
-
+-----------------------------------------------------+
| Length(24) |
+---------------+----------------+--------------------+
| Type(8) | Flags(8) |
+---------------+----------------+--------------------------------------+
|R| Stream Identifier(31) |
+=+=====================================================================+
| Frame Payload(0...) ...
+-----------------------------------------------------------------------+
nginx中调用ngx_http_v2_get_frame生成一个帧结构,并填充帧头
static ngx_http_v2_out_frame_t *
ngx_http_v2_get_frame(ngx_http_v2_connection_t *h2c, size_t length,
ngx_uint_t type, u_char flags, ngx_uint_t sid)
{
...
frame = h2c->free_frames;
// 获取或生成一个帧结构体
...
frame->length = length;
// 填充长度和类型 共32位
buf->last = ngx_http_v2_write_len_and_type(buf->pos, length, type);
// 8位的flag
*buf->last++ = flags;
// 1位R 和 31位的流标志ID
buf->last = ngx_http_v2_write_sid(buf->last, sid);
return frame;
}
http1.1是明文协议,其格式由三部分组成:start line(request line或者status line),header,body。要识别这3部分就要做协议解析,而基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多。二进制则不同,只认0和1的组合。基于这种考虑http2.0的协议解析决定采用二进制格式,实现方便且健壮。
http/2.0 所有性能增强的核心在于心的二进制分帧层,它定义了如何封装http消息并在客户端和服务端之间传输。
http2会发送有着不同类型的二进制帧,但他们都有这5个公共字段:Type, Length, Flags, Stream Identifier和frame payload。
规范中一共定义了10种不同的帧,其中最基础的两种分别对应于HTTP 1.1的DATA和HEADERS。虽然协议的格式和http1.1完全不同,实际上http2.0并没有改变http1.1的语义,只是把原来http1.1的header和body部分用frame重新封装了一层而已。
-
连接的多路复用。 在http/1.x中,如果客户端想要发起多个并行请求以提升性能,则必须使用多个tcp连接。 二进制协议中的Stream Identifier字段就是用作连接共享机制的。一个request对应一个stream并分配一个Identifier,这样一个连接上可以有多个stream,每个stream的frame可以随机的混杂在一起,接收方可以根据Stream Identifier将frame再归属到各自不同的request里面。
-
支持优先级和依赖。 http2.0里的每个stream都可以设置优先级(Priority)和依赖(Dependency)。优先级高的stream会被server优先处理和返回给客户端,stream还可以依赖其它的sub streams。优先级和依赖都是可以动态调整的。动态调整在有些场景下很有用,假想用户在用你的app浏览商品的时候,快速的滑动到了商品列表的底部,但前面的请求先发出,如果不把后面的请求优先级设高,用户当前浏览的图片要到最后才能下载完成,显然体验没有设置优先级好。同理依赖在有些场景下也有妙用。
-
头压缩。 HTTP1.1的header带有大量信息,而且每次都要重复发送,HTTP2.0使用HPACK压缩算法来减少需要传输的header大小。通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
-
重置连接。 很多使用场景有取消图片下载的功能,对于http1.1来说最终解决方案都会导致断开连接,下次再发请求就必须重新建立连接。而http2.0引入RST_STREAM类型的frame,可以在不断开连接的前提下取消某个request的stream。从而避免浪费带宽和中断已有的连接。
-
流量控制。 流量控制是基于每一跳,而非端到端的。 基于窗口更新帧,接收方通告接收窗口。
-
服务器推送。 服务器可以对一个客户端请求发送多个响应。
协议
现状
到目前为止几乎所有的主流浏览器和web服务器都支持http2.0,iOS9+也支持http2.0了。
参考
https://skyao.io/learning-http2/introduction/information.html