前端
network
HTTP1.1 & HTTP2

HTTP/1.1 相较于 HTTP/1.0 的改进和优化:

  • 持久连接
  • HTTP 管道化
  • 分块编码传输
  • 新增 Host 头处理
  • 更多缓存处理
  • 新增更多状态码
  • 断点续传、并行下载

HTTP/1.1 的缺点:

  • 队头阻塞
  • 首部冗余(报文主体进行了压缩,但是首部没压缩)
  • TCP 连接数受各家浏览器限制,连接过多的话可能会导致 DDOS 攻击

持久连接:在 HTTP/1.0 时期,每进行一次 HTTP 通信,都需要经过 TCP 三次握手建立连接。若一个页面引用了多个资源文件,就会极大地增加服务器负担,拉长请求时间,降低用户体验。HTTP/1.1 中增加了持久连接,可以在一次 TCP 连接中发送和接收多个 HTTP 请求/响应。只要浏览器和服务器没有明确断开连接,那么该 TCP 连接会一直保持下去。持久连接在 HTTP/1.1 中默认开启(请求头中带有 Connection: keep-alive),若不需要开启持久连接,可以在请求头中加上 Connection: close。

HTTP 管道化 :指的是单个连接发送多个请求,但是响应时必须按照发送的顺序接收,这就会造成很大的执行难度,网络情况很难预知,有可能第一个要收到的响应丢包了,然后第二个响应变成第一个接收到的,所以我们比较难看到有浏览器会实际使用这个技术。在网络层面开发者无法解决这个问题,在开发方面就多了很多手段来处理,比如精灵图(雪碧图),但是这对于开发者的开发体验来说是很差的,除此之外,Data URLs 是另一种替代方案,将图片用 base64 进行编码,然后写进 HTML ,但是一般 base64 编码后的图片会比原图大 30% 左右,并且编码结果会很长,很不方便代码的维护和管理。

分块编码传输:在 HTTP/1.1 协议里,允许在响应头中指定 Transfer-Encoding: chunked 标识当前为分块编码传输,可以将内容实体分装成一个个块进行传输。

新增 Host 头处理:在 HTTP/1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此一台服务器也无法搭建多个 Web 站点。在 HTTP/1.1 中新增了 host 字段,可以指定请求将要发送到的服务器主机名和端口号。

断点续传、并行下载:在 HTTP/1.1 中,新增了请求头字段 Range 和响应头字段 Content-Range。前者是用来告知服务器应该返回文件的哪一部分,后者则是用来表示返回的数据片段在整个文件中的位置,可以借助这两个字段实现断点续传和并行下载。

队头阻塞:当一个 TCP 连接上有多个请求时,如果前面的请求没有响应,后面的请求就会一直等待,这就是队头阻塞。HTTP/1.1 在请求一个网页时,先请求获取网页的 HTML,然后再根据 HTML 里的内容再向服务器依次请求 CSS、JS、图片等资源,如果在请求队伍里,有一个资源没有收到,那么后面的资源也没法接收了。即使有多个连接,还是有问题,假设浏览器其他连接的响应文件都收到了,就只有一个连接的资源没有收到,刚好是个会导致浏览器没发渲染的 CSS 资源,那么浏览器就会一直等待,也会发生队头阻塞。

首部冗余:HTTP 请求每次都会带上请求头,请求头没有进行压缩,若此时 cookie 也携带大量数据时,就会使得请求头部变得臃肿。

TCP 连接数:TCP 连接数实际上是浏览器限制每个域的连接数,所以也有种处理方法是分成多个二级域名,然后同时下载,这种操作也并不推荐,开发的复杂度被硬生生的提高了。

HTTP/2 的特点:

  • 二进制分帧层
  • 多路复用
  • Header 头部压缩
  • 服务端推送

二进制分帧层:在 HTTP/1.x 中传输数据使用的是纯文本形式的报文,需要不断地读入字节直到遇到分隔符为止。而 HTTP/2 则是采用二进制编码,将请求和响应数据分割为一个或多个的体积小的帧。帧分为首部帧和数据帧,首部帧包含了请求和响应的元数据,数据帧则包含了请求和响应的数据。

多路复用:HTTP/2 的多路复用是指在一个连接里面,客户端和服务器都可以同时发送多个请求或者响应,而且不用按照顺序一一对应,只需要按照帧内的流标识进行关联就可以了,这样就避免了 HTTP/1.x 中队头阻塞的问题。但是这里还是有一个坑,详见下面 HTTP/3。

Header 头部压缩:引入了 HPACK 算法进行压缩头部内容,HPACK 算法要求浏览器和服务器维护一张静态只读的表,比如经典的 "HTTP/1.1 200 OK" 起始行,在 HTTP/2 里就变为了 ":status:200",虽然从肉眼看只少了 3 个字节,但是是重复的首部,可以实现在二次请求和响应里直接去掉,另外,cookie 这样的动态信息可以加入动态表里,这样能节省下来的资源还是很可观的。

服务端推送:HTTP/2 中引入了服务端推送,可以在客户端请求 HTML 时,将 HTML 中引用的 CSS、JS、图片等资源一并推送给客户端,这样就可以避免客户端再次发起请求。看上去很美好但是有可能用户不小心点错了一个网页,但是却多了一堆缓存。这里还有可能会造成 DDOS 非对称攻击,应为这里存在一个明显的“杠杆”。因为服务器推送也隐含着安全性的问题。

HTTP/3:

在 HTTP/2 中,HTTP/2 只解决了应用层的队头阻塞问题,但是 HTTP 下来到 TCP 层进行传输时,TCP 才不知道帧里面的内容,TCP 还是会按照顺序传输,举个极端点的例子,即使在传输过程中丢失的代码是一段注释,也需要进行重传,这就是 TCP 层面的队头阻塞。比较好的办法就是把 TCP 也变成 HTTP/2 帧那样进行传输,但是关键是 TCP 协议是由操作系统内核实现的,除非让整个世界的大部分操作系统都进行一次革新的升级,那不知道得等到什么时候了。所以 这就是为什么 HTTP/3 选择 UDP 协议来实现的原因,并且在 UDP 上新增了一个协议,也就是 QUIC 协议。