HTTP1.0 HTTP1.1 HTTP2.0 主要特性对比

HTTP发展历史

  • HTTP/0.9 (1989)
    短连接,无状态,它只有一个 GET 方法, 没有首部, 设计目标是获取HTML(没有图片, 只有文本)
  • HTTP/1.0 (1996)
    在 HTTP/0.9 版本的基础上新增了大量内容,加入了许多重要概念:
    • 首部
    • 响应码
    • 重定向
    • 错误
    • 条件请求
    • 内容编码(压缩)
    • 更多的请求方法 …
  • HTTP/1.1 (1999)
    在 HTTP/1.0 版本的基础上添加:
    强制要求客户端提供 Host 首部, 这使虚拟主机托管成为可能(在一个IP上提供多个web服务)。 当使用新的连接指令时, Web 服务器不需要在每个响应之后关闭连接。添加的变更如下:
    • 缓存相关首部的扩展
    • OPTIONS 方法
    • Upgrade 首部
    • Range 请求
    • 压缩和传输编码(Transfer-encoding)
    • 管道化(pipelining)
    • 长链接
  • SPDY (2009)
    Google 工程师提出了一种替代 HTTP 的方案: SPDY 不是第一个希望替代 HTTP 的方案, 但它是其中最重要的一个, 因为它带来了显而易见的性能提升. 它是 HTTP/2 的基础.
  • HTTP/2 (2015)
    RFC 7540 在 2015 年 5 月 14 日发布了HTTP/2的正式协议. 期望:
    • 相比于使用 TCP 的 HTTP/1.1, 最终用户可感知的多数延迟都有能够量化的显著改善
    • 解决 HTTP 中的队头阻塞问题
    • 并行的实现机制不依赖与服务器建立多个连接, 从而提升 TCP 连接的利用率, 特别是在拥塞控制方面
    • 保留 HTTP/1.1 的语义, 可以利用已有的文档资源, 包括(但不限于) HTTP 方法, 状态码, URI 和首部字段
    • 明确定义 HTTP/2.0 和 HTTP/1.x 交互的方法, 特别是通过中介时的方法(双向)
    • 明确指出它们可以被合理使用的新的扩展点和策略

HTTP2解决的问题

    • 队头阻塞
      服务端收到多个管道请求后,需要按接收顺序逐个响应。如果恰好第一个请求特别慢,后续所有响应都会跟着被阻
    • TCP利用低效
      h1 并不支持多路复用, 所以浏览器一般会针对指定域名开启6个并发连接。这意味着 多个TCP连接(同域名6个)dns开销;TCP拥塞控制经过多个RTT才能达到理想的吞吐量
    • 消息头冗余
      HTTP/1 协议头部使用纯文本格式,没有任何压缩,且包含很多冗余信息(例如 Cookie、UserAgent 每次都会携带),所以一个页面的请求数越多,头部带来的额外开销就越大(使用短小和多个域名)
    • 优先级设置受限
      浏览器为了先请求优先级高的资源, 会推迟请求其他资源. 但优先级高的资源获取后, 在处理的过程中, 浏览器并不会发起新的资源请求, 所以服务器无法利用这段时间发送优先级低的资源, 总的页面下载时间因此延长了; 一个高优先级资源被浏览器发现后, 但受制于浏览器处理的方式, 它被排在了一个正在获取的低优先级资源之后

HTTP1.0

早先1.0HTTP版本,是一种无状态、无连接的应用层协议。

HTTP1.0规定浏览器和服务器保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立即断开TCP连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态)。

这种无状态性可以借助cookie/session机制来做身份认证和状态记录。而下面两个问题就比较麻烦了。

首先,无连接的特性导致最大的性能缺陷就是无法复用连接。每次发送请求的时候,都需要进行一次TCP的连接,而TCP的连接释放过程又是比较费事的。这种无连接的特性会使得网络的利用率非常低。

其次就是队头阻塞(head of line blocking)。由于HTTP1.0规定下一个请求必须在前一个请求响应到达之前才能发送。假设前一个请求响应一直不到达,那么下一个请求就不发送,同样的后面的请求也给阻塞了。

为了解决这些问题,HTTP1.1出现了。

HTTP1.1

对于HTTP1.1,不仅继承了HTTP1.0简单的特点,还克服了诸多HTTP1.0性能上的问题。

首先是长连接,HTTP1.1增加了一个Connection字段,通过设置Keep-Alive可以保持HTTP连接不断开,避免了每次客户端与服务器请求都要重复建立释放建立TCP连接,提高了网络的利用率。如果客户端想关闭HTTP连接,可以在请求头中携带Connection: false来告知服务器关闭请求。

其次,是HTTP1.1支持请求管道化(pipelining)。基于HTTP1.1的长连接,使得请求管线化成为可能。管线化使得请求能够“并行”传输。举个例子来说,假如响应的主体是一个html页面,页面中包含了很多img,这个时候keep-alive就起了很大的作用,能够进行“并行”发送多个请求。(注意这里的“并行”并不是真正意义上的并行传输,具体解释如下。)

需要注意的是,服务器必须按照客户端请求的先后顺序依次回送相应的结果,以保证客户端能够区分出每次请求的响应内容。

也就是说,HTTP管道化可以让我们把先进先出队列从客户端(请求队列)迁移到服务端(响应队列)。

HTTP1.0 HTTP1.1 HTTP2.0 主要特性对比

如图所示,客户端同时发了两个请求分别来获取htmlcss,假如说服务器的css资源先准备就绪,服务器也会先发送html再发送css

换句话来说,只有等到html响应的资源完全传输完毕后,css响应的资源才能开始传输。也就是说,不允许同时存在两个并行的响应。

可见,HTTP1.1还是无法解决队头阻塞(head of line blocking)的问题。同时“管道化”技术存在各种各样的问题,所以很多浏览器要么根本不支持它,要么就直接默认关闭,并且开启的条件很苛刻...而且实际上好像并没有什么用处。

那我们在谷歌控制台看到的并行请求又是怎么一回事呢?

HTTP1.0 HTTP1.1 HTTP2.0 主要特性对比

如图所示,绿色部分代表请求发起到服务器响应的一个等待时间,而蓝色部分表示资源的下载时间。按照理论来说,HTTP响应理应当是前一个响应的资源下载完了,下一个响应的资源才能开始下载。而这里却出现了响应资源下载并行的情况。这又是为什么呢?

其实,虽然HTTP1.1支持管道化,但是服务器也必须进行逐个响应的送回,这个是很大的一个缺陷。实际上,现阶段的浏览器厂商采取了另外一种做法,它允许我们打开多个TCP的会话。也就是说,上图我们看到的并行,其实是不同的TCP连接上的HTTP请求和响应。这也就是我们所熟悉的浏览器对同域下并行加载6~8个资源的限制。而这,才是真正的并行!

此外,HTTP1.1还加入了缓存处理(强缓存和协商缓存[传送门])新的字段如cache-control,支持断点传输,以及增加了Host字段(使得一个服务器能够用来创建多个Web站点)。

HTTP2.0

HTTP2.0的新特性大致如下:

二进制分帧

HTTP2.0通过在应用层和传输层之间增加一个二进制分帧层,突破了HTTP1.1的性能限制、改进传输性能。

HTTP1.0 HTTP1.1 HTTP2.0 主要特性对比

可见,虽然HTTP2.0的协议和HTTP1.x协议之间的规范完全不同了,但是实际上HTTP2.0并没有改变HTTP1.x的语义。
简单来说,HTTP2.0只是把原来HTTP1.xheaderbody部分用frame重新封装了一层而已。

多路复用(连接共享)

下面是几个概念:

  • 流(stream):已建立连接上的双向字节流。
  • 消息:与逻辑消息对应的完整的一系列数据帧。
  • 帧(frame):HTTP2.0通信的最小单位,每个帧包含帧头部,至少也会标识出当前帧所属的流(stream id)。

HTTP1.0 HTTP1.1 HTTP2.0 主要特性对比

从图中可见,所有的HTTP2.0通信都在一个TCP连接上完成,这个连接可以承载任意数量的双向数据流。

每个数据流以消息的形式发送,而消息由一或多个帧组成。这些帧可以乱序发送,然后再根据每个帧头部的流标识符(stream id)重新组装。

举个例子,每个请求是一个数据流,数据流以消息的方式发送,而消息又分为多个帧,帧头部记录着stream id用来标识所属的数据流,不同属的帧可以在连接中随机混杂在一起。接收方可以根据stream id将帧再归属到各自不同的请求当中去。

另外,多路复用(连接共享)可能会导致关键请求被阻塞。HTTP2.0里每个数据流都可以设置优先级和依赖,优先级高的数据流会被服务器优先处理和返回给客户端,数据流还可以依赖其他的子数据流。

可见,HTTP2.0实现了真正的并行传输,它能够在一个TCP上进行任意数量HTTP请求。而这个强大的功能则是基于“二进制分帧”的特性。

头部压缩

HTTP1.x中,头部元数据都是以纯文本的形式发送的,通常会给每个请求增加500~800字节的负荷。

比如说cookie,默认情况下,浏览器会在每次请求的时候,把cookie附在header上面发送给服务器。(由于cookie比较大且每次都重复发送,一般不存储信息,只是用来做状态记录和身份认证)

HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。高效的压缩算法可以很大的压缩header,减少发送包的数量从而降低延迟。

服务器推送

服务器除了对最初请求的响应外,服务器还可以额外的向客户端推送资源,而无需客户端明确的请求。

HTTP1.1的合并请求是否适用于HTTP2.0

首先,答案是“没有必要”。之所以没有必要,是因为这跟HTTP2.0的头部压缩有很大的关系。

在头部压缩技术中,客户端和服务器均会维护两份相同的静态字典和动态字典。

在静态字典中,包含了常见的头部名称以及头部名称与值的组合。静态字典在首次请求时就可以使用。那么现在头部的字段就可以被简写成静态字典中相应字段对应的index

而动态字典跟连接的上下文相关,每个HTTP/2连接维护的动态字典是不尽相同的。动态字典可以在连接中不听的进行更新。

也就是说,原本完整的HTTP报文头部的键值对或字段,由于字典的存在,现在可以转换成索引index,在相应的端再进行查找还原,也就起到了压缩的作用。

所以,同一个连接上产生的请求和响应越多,动态字典累积得越全,头部压缩的效果也就越好,所以针对HTTP/2网站,最佳实践是不要合并资源。

另外,HTTP2.0多路复用使得请求可以并行传输,而HTTP1.1合并请求的一个原因也是为了防止过多的HTTP请求带来的阻塞问题。而现在HTTP2.0已经能够并行传输了,所以合并请求也就没有必要了。

总结

HTTP1.0

  • 无状态、无连接

HTTP1.1

  • 持久连接
  • 请求管道化
  • 增加缓存处理(新的字段如cache-control
  • 增加Host字段、支持断点传输等

HTTP2.0

    • 二进制分帧
    • 多路复用(或连接共享)
    • 头部压缩
    • 服务器推送

refer:

https://segmentfault.com/a/1190000013028798

https://zhuanlan.zhihu.com/p/39053130

更多参考:https://www.it610.com/article/1279366019483189248.htm