Loading

HTTP发展历程

为了满足好奇心吧, 简单介绍下HTTP的各个版本. 了解HTTP协议是如何一步步发展至今的.

这篇文章不会涉及太多原理

HTTP/0.9

HTTP/0.9 诞生于1991年, 甚至都没有RFC标准, 就是一个简单的文档.

这个版本的HTTP协议, 只是简单规定了:

  • 请求内容为: GET /a/b/c.html
  • 默认端口80
  • 响应内容直接传输字符流

没了. 注意, 此时还没有请求体. 就是单纯的请求HTML页面, 相当之简单了.

HTTP/1.0

随着互联网的发展, 只是单纯的HTML页面已经不能满足当下的需求了. 还需要js/css/img/audio等等资源文件.

那么, 如何使得HTTP协议能够传输多种文件类型呢? HTTP/1.0登场了, 1.0版本也有了对应的RFC 文档.

简单说来, 这个版本已经是我们常见的格式了, 其请求内容如:

// 请求信息: 
GET /favicon.ico HTTP/1.0
Accept: image/avif
// 响应信息
HTTP/1.1 200 OK
Content-Length: 19933
Content-Type: image/gif

增加的内容大致如下:

  1. 增加了请求header.
  2. 响应内容增加了响应码
  3. 请求方式不再局限于GET, 增加了POST PUT

这样一来, 就更加灵活了, 比如:

  1. POST等方法增加了请求的灵活性
  2. 增加了响应码, 当请求失败的时候, 可以通过响应码传递失败原因
  3. header 的增加使得请求和响应可以传递各种各样协商好的信息, 比如:
    • 指定文件类型
    • 指定压缩算法, 可以减少体积, 降低网络传输时间
    • 灵活的 header 也为未来的升级做好了支持

HTTP/1.1

HTTP/1.0最大的问题是传输速率. 每次发起一个请求, 都要经过 TCP 三次握手->数据传输->TCP挥手的完整过程. 随着页面要加载的文件越来越多, 就导致了页面加载时间较长. 因此, 升级后多个请求可公用一个 TCP 连接, 省掉了频繁建立和释放连接的时间.

不过HTTP/1.1的请求体与响应体倒没有什么大的变化, 升级主要通过header实现.

简单列举一些新增的header:

  • Connection: 标记连接方式, keep-alive开启持久连接. 比如谷歌浏览器针对每个域名会同时开启6个 TCP 连接
  • Host: 标记域名, 可支持多个域名同一 IP
  • Cookie: 增加客户端的数据存储
  • Cache-Control: 浏览器缓存静态资源

更详细的内容可查看RFC 文档, HTTP/1.1`协议每隔几年就会进行更新, 其目前的更新文档那个大致如下: 1997年1月 - 1999年6月 - 2014年6月 - 2022年6月

HTTP/1.1版本也是现在普遍使用的版本了.

HTTP/2

那么HTTP/1.1已经完美了么? 这世上哪会有完美的东西, HTTP/1.1还存在以下问题(可能列举的并不全面):

  1. 连接阻塞.
    • HTTP/1.1多个请求可以复用同一个 TCP 连接, 但是多个请求是顺序请求的
    • 如果一个请求阻塞了5秒, 那么后面排队的请求都要延迟等待5秒. (这就是浏览器F12看到的请求排队时间)
  2. 无法指定请求的优先级.
    • HTTP/1.1中发起多个请求时, 无法指定请求的顺序.
    • 比如在一个页面中, js/css等文件下载完毕, 页面整体就已经可以限时了, 图片/音频/视频 等内容的优先级可以低一些.
  3. HTTP/1.1是单向通信的, 服务器无法主动给浏览器发送消息.
  4. 等等

为了解决这些问题, 推出了HTTP/2. 其前身是谷歌的实验性协议SPDY.

HTTP/21.1的基础上, 增加了:

  • 多路复用. 多个请求复用同一个 TCP连接时, 无需排队, 可以并行发送. 给每个响应包标识请求 ID, 浏览器拿到后再进行组装
    • 也基于此, 浏览器也无需开启多个 TCP 连接了, 所有请求可以公用同一个 TCP 连接. 也减少了多个连接的网络竞争.
  • 可以设置请求的优先级. 可以给请求设置不同的权重, 以优先响应高权重的请求
  • 允许服务器主动推送. 注意, 这个推送可不是websocket.
    • 浏览器请求HTML页面的时候, 解析后发现还需要请求相关的js/css文件, 然后再去请求资源文件. 这中间就存在一定的时间消耗
    • 现在, 浏览器请求HTML页面的时候, 服务器可以同时将相关的资源文件主动发给浏览器, 极大缩短页面的加载时间.
  • 头部压缩. 每个请求都会携带请求头, 如果请求头中存在Cookie可能就更大了.
  • 为了减少这些开销, HTTP/2使用HPACK对请求头及响应头进行压缩. (其实就是个霍夫曼编码)

等等吧, 更加详细的内容请查看其RFC 文档. 据说升级HTTP/2之后能够带来20%~60%的效率提升.

另外, 我找到了一份HTTP/2各个语言的实现列表, 可以简单看一下.

HTTP/3

HTTP/2还没普及, 就已经推出新的协议来解决HTTP/2的问题了. 那么HTTP/2存在什么问题呢?

  1. TCP丢包阻塞.
    • TCP 连接为了保证传输数据的顺序与可靠, 当出现丢包时会进行重传.
    • HTTP/2使用同一个 TCP 连接发送多个请求的数据
    • 一旦其中一个请求发生丢包, 就会阻塞该连接的所有后续请求
    • 这不同于HTTP/1.1的阻塞. HTTP/1.1的阻塞是应用层的阻塞, 而HTTP/2的阻塞是传输层的阻塞.
    • 据说, 经过测试, 当连接的丢包率大于2%时, HTTP/2的性能会低于HTTP/1.1. 不过我没有找到测试数据.
  2. 建立连接耗时.
    • TCP 请求的建立需要通过三次握手. 需要1.5RTT(往返时间)
    • 如果使用 HTTPS 协议, 那么 TLS 也需要握手, TLS1.3需要2次, 即1RTT
    • 那么每次建立请求都需要3.5RTT, 网速较慢时, 握手时间甚至可能长达300ms

那么如果解决这些问题呢? 可以看到, 问题主要发生在传输层, TCP协议是无法轻易改动了. 此时, 又是谷歌出手了, 设计了QUIC, 采用UDP 进行数据传输. 在应用层来实现了原来传输层的功能. 因为基于 UDP 实现, 甚至握手阶段可以做到0RTT.

RFC 在今年六月份发布的HTTP/3也正是基于QUIC.

其使用 UDP 替换了 TCP 协议, 至于其具体的实现原理, 暂时按下不表. 感兴趣的可以查看其RFC 文档详细了解.


对于我们日常开发来说, 优化的方向更多是在接口本身的响应时间. 但同时, 已经有先驱们在想着如何让数据传输的更快了, 膜拜. 不过要想等到HTTP/2 HTTP/3普及, 估计也是 n 年后的事情了吧.

原文地址: https://hujingnb.com/archives/875

posted @ 2022-12-14 23:28  烟草的香味  阅读(61)  评论(0编辑  收藏  举报