HTTP 2.0 杂谈

HTTP2

正经的开场

当前互联网大部分的内容都使用 HTTP1.1 作为通信协议。大家在这项协议上投入了非常多的“精力”,比如从 HTTP1.0 规范的 60 页暴涨到 HTTP1.1 规范的 176 页。相信大部分人都没有兴趣完整的阅读完这份规范,这样导致的结果就是 HTTP1.1 中的很多细节都没有被很好的实现,即使一开始实现的功能也很少被使用。而随着时间推移…使用者才发现,原来这货有这么多毛病。

HTTP1.1 的功与过

但在挑毛病之前,我们先来看看它相对于 HTTP1.0 有哪些改进之处:

  1. 缓存处理,HTTP1.0中使用 If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
  2. 带宽优化及网络连接的使用,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
  3. 错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
  4. Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
  5. 长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。以下是常见的HTTP1.0:

好了,虽然 HTTP1.1 改进了很多问题,但吃瓜群众是永远不会满足的。于是他们抛出了更多问题:

  1. HTTP1.1 在传输数据时,每次都需要重新建立连接,无疑增加了大量的延迟时间,特别是在移动端更为突出。
  2. HTTP1.1 在传输数据时,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份,这在一定程度上无法保证数据的安全性。
  3. HTTP1.1 在使用时,header里携带的内容过大,在一定程度上增加了传输的成本,并且每次请求header基本不怎么变化,尤其在移动端增加用户流量。
  4. 虽然 HTTP1.1 支持了 keep-alive,来弥补多次创建连接产生的延迟,但是keep-alive使用多了同样会给服务端带来大量的性能压力,并且对于单个文件被不断请求的服务(例如图片存放网站),keep-alive可能会极大的影响性能,因为它在文件被请求之后还保持了不必要的连接很长时间。

HTTP2 背景介绍

终于“讲完”了 HTTP1.1,该轮到本篇博客的主角登场了——HTTP2
HTTP2 其实是起源于一个叫 SPDY 的协议,这是由 Google 牵头开发的。HTTP2 就是在这个协议的基础上修修改改发布的。不过 Chrome 已经移除了 SPDY,就不说这货了。

HTTP2 必须维持原有的 HTTP1.1 的形式,不该改变URL结构,也不能新增结构。比较老的协议还有很多人用。

这就出现了第一个问题,浏览器怎么知道是 HTTP2 是 HTTP1.1 ?
于是规范和产商就开始撕逼了,规范表示,提供一个首部字段,表示允许服务器在收到旧协议请求的同时,可以向客户端发送新协议的内响应,但这一方案需要花费一次额外的往返通信来作为升级代价。
Google 团队很不爽,觉得这方案太次了,于是就自己搞了个 TLS 的拓展,功能是服务器可以通知客户端所有它支持的协议,让客户端自己选。

于是 Chrome 实现的 HTTP2 只能使用 TLS,也就是 HTTPS。但规范是普通的 HTTP 也能使用。这时候各家浏览器大佬纷纷跳出了站队了。Firefox 大佬表示,我跟 Chrome。这一点其实有点出乎意料,Firefox 不是曾经号称最遵循规范的浏览器嘛,不过也可能因为 Firefox 是开源的,成员为了节省精力吧。然后这时候微软也跳了出来,老子就跟你们不一样,老子就要支持普通 HTTP 的 2.0!!!

进击的 HTTP2

Frame 帧

HTTP2 能有那么多新特性,最主要的功臣就是改变了数据传输的格式,变成了二进制,二进制格式在协议的解析和优化扩展上带来更多的优势和可能。 Frame 是 HTTP/2 二进制格式的基础,基本可以把它理解为它 TCP 里面的数据包一样。HTTP/2 之所以能够有如此多的新特性,正是因为底层数据格式的改变。

Multipexing 多路复用

网页加载速度慢的罪魁祸首可以说是延迟了,所有的优化都是为了降低延迟,在 HTTP1.1 中虽然一个 TCP 连接可以发送多个请求,但还是有上限的,从一开始的两个,到五个…于是就萌生了各种减少请求数的方法,包括雪碧图,内联小图片,合并 CSS、JS,分片(Sharding)就是把你的服务分散在尽可能多的主机上。
但这些方法都有一定的副作用,并不能百分百解决问题。
于是 HTTP2 实现了让所有请求跑在一条 TCP 连接上,而且没有请求数量上限。

Priority 优先级

每个流都有一个优先级值,用来告诉对端来说哪个流更重要。当资源有限时,服务器会根据优先级来选择优先发送哪个流。客户端通用可以告知服务端哪个流优先级高,这个流依赖了哪些流,在传输的过程中,这个优先级也可以被动态的改变。

Header 头压缩

HTTPS 和 SPDY 的压缩机制都被发现有受 BREACHCRIME 攻击的隐患。通过向流中注入一些已知文本来观察输出的变化,攻击者可以从加密的载荷中推导出原始发送的数据。
HPACK 是专为 HTTP2 设计的压缩格式。引入了一些新的对策来让破解压缩更加困难。如采用帧的可选填充和用一个 bit 作为标记。

Server Push 服务器推送

这个简单举个例子就是服务器在发送 html 文件的同时把这个 html 要用到的 css 和 js 文件也推送给了浏览器,这样不需要等到浏览器解析了 html 文件才发出 css 和 js 的资源请求。

Reset 重置

HTTP1.1 在发出含有确切的Content-Length 的 HTTP 消息之后,你就很难中断它了,除非断掉 TCP 连接,但这意味着你得重新三次握手建立一个新连接。
在 HTTP2 里可以发送一个 RST_STREAM 帧来终止当前传输的消息而不断开 TCP 连接。

了解更多: