leevis.com icon indicating copy to clipboard operation
leevis.com copied to clipboard

http2.0介绍

Open vislee opened this issue 8 years ago • 0 comments

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

vislee avatar Feb 15 '17 04:02 vislee