HTTP 从 1 到 2 再到 3
当前我们常用的 HTTP 是一种基于TCP 协议栈的协议,因此 HTTP 协议必不可少要受到了 TCP 协议的影响,现在就让我们开始了解 TCP 的特性到底影响了 HTTP 协议的哪些方面?我们从 HTTP 的不足入手,再一步一步从 HTTP0.9 前进到 HTTP3 时代。
HTTP 1
HTTP0.9 是最初的简单版本,在那个时代背景下(1991 年),浏览器还没有得到广泛使用,其主要目的是被用于学术间的交流传输超文本文件,因为需求简单,其甚至都不存在请求头等复杂配置,只需要一个请求行而响应则只需要直接把超文本文件的数据以 ASCII 字节码的形式回传即可,当然,这时候其底层依托的也是 TCP 协议。
到了浏览器开始展露苗头时,我们需要使用 HTTP 协议传输的文件类型就变多了,仅靠一个请求行和响应直接回送数据是远远不够的了,于是 HTTP1.0 应运而生,我们现如今熟悉的 HTTP 协议中的很多内容都是在这个时刻中诞生的。
HTTP1.0 为 HTTP 协议引入了请求头和响应头、状态码、缓存机制(用 If-Modified-Since,Expires 来做为缓存判断的标准),现在请求和响应可以交互了,在简单的网站上我们可以使用 HTTP 协议来传输各种类型的文件,如 CSS 样式表、JS 脚本文件、图像等,我们还可以规定数据的编码、压缩格式等等,这时 HTTP 协议已经具备了雏形。但 HTTP1.0 的缺点也是很明显的,比如:
- 不支持长连接,每一次 HTTP 请求都需要重新建立 TCP 连接
- 不支持文件部分数据传输和断点传输
- 不支持多个域名同一 IP,即认为每一个 HOST 都对应了一个独特的 IP
为了解决这些问题,HTTP1.1 就对其做出了一定的修改和完善:
- 丰富状态码,还提供了 100 状态码,这样客户端会预先发送一个带部分请求体的请求,在得到服务器 100 响应后才会正式地发送剩余的完整数据,避免因为服务器拒绝而浪费了太多资源
- 增加 HOST 字段,用来标识域名,解决了一个 IP 对应一个域名的问题
- 使用 keep-alive 字段保持长连接,让一个 TCP 连接上可以跑多个 HTTP 请求,这样就避免了重复的无效请求还要忍受 TCP 慢启动的折磨
- 使用 range 头域、content-range 头来实现文件部分内容传输和断点重传
还增加了 cookie 机制,再引入 Chunk transfer 机制实现了对动态内容的支持,动态内容即传输时并不知道具体的长度,利用最后一个包携带的结束标识判断是否传输完毕,有了这些功能后的 HTTP 协议开始发挥功力,得到了广泛的应用,并沿用至今,但其受 TCP 的影响还有一些不得不面对的大问题:队头阻塞、TCP 慢启动、多条 TCP 连接竞争带宽
- 队头阻塞:TCP 是一种有序的可靠传输,因此当出现丢包时,TCP 就会中断后续的请求,重新回送丢包的数据,这样也就导致了后续请求被阻塞,影响页面加载的性能。
- TCP 慢启动:TCP 为了避免网络拥塞,使用了多种手段来动态适应各种网络状况,尽可能避免出现网络风暴,而慢启动就是其中的一种策略,其核心是通过逐次增加 TCP 请求数量来检测当前网络情况,通常要经过多个回合才能达到正常的请求发送速度,而我们页面加载文件越多,就越会受到这个策略的影响
- 多条 TCP 连接竞争带宽,在 chrome 浏览器中允许一个域名建立六条 TCP 连接,在 HTTP1.1 协议下一条 TCP 连接上处理单条 HTTP 连接,而这六条连接会竞争带宽,导致带宽无法被完全用满,如果有多余的请求要建立连接也会被阻塞
HTTP-SPDY优化方案(由 google 强势推出):
- 使用多个 Stream 让单条 TCP 上能处理多条 HTTP 请求,还可以设置请求优先级
- Header 压缩,因为每条请求都要用到 Header,对其进行压缩能很好节约资源
- 使用预推送,在请求 a.html 时服务器可以知道后面可能需要 a.css 和 a.js,则响应上会捎带这些消息
- 基于 HTTPS的传输加密
HTTP 2
HTTP2 可以看成是 HTTP-SPDY的进一步升级版本,主要目的是在基于TCP 协议栈的基础上提升 HTTP1.X 的性能,其和SPDY不同的点在于并不强制要求使用HTTPS保证传输的安全性,Header 的压缩算法也不一样。
- HTTP2 传输文件使用的是新的二进制文件格式,而不是 HTTP1.0 的基于文本的形式,即 HTTP2 实现了一个二进制帧处理层,还可以用来做到多路复用。
- 多路复用是使用 Stream 配合 ID 实现的,在传输数据时二进制帧处理层会添加一个 ID,同一份文件的 ID 是相同的,在接收后只需要重新组合。多路复用的另一个好处是可以实现同一条 TCP 连接中传输多条 HTTP 请求,而且可以做到并发,解决了带宽竞争、慢启动的问题
HTTP2 也是“渐进式”的,兼容 HTTP1.X 版本的,对于不兼容 HTTP2 的浏览器服务器端也是可以通过配置实现自动向下兼容的。但 HTTP2 依托的仍然是 TCP 协议,因此还是会存在队头阻塞的问题,而且由于只存在一条 TCP 连接,在丢包率达到 2%的情形下,HTTP1.1 协议(同一域名 6 条 TCP 连接)的性能要比 HTTP2.0 好!
HTTP 3
HTTP3 是一种颠覆性的协议,因为其底层使用了QUIC(Quick UDP Internet Connection)顾名思义,QUIC 又是一种基于 UDP 的协议,TCP 与 UDP 这两种协议总是被放在一起做比较,QUIC 就是在 UDP 的基础上模拟 TCP,实现了部分 TCP 的功能,这样就能做到在速度和可靠间平衡,其主要的功能有:
- 可靠传输和流量控制,在 UDP 上又封装了一层,以实现包重传和拥塞控制
- 集成 TLS 加密,目前使用 TLS1.3 协议,减少建立握手的过程
- 实现 HTTP2 的多路复用,但这里可以像 HTTP1.1 一样建立多条物理连接,从而避免了队头阻塞的问题
结尾
HTTP/TCP 协议是成为一名优秀的前端工程师要深入了解的知识,这篇文章也只是管中窥豹,大概的浏览了一下 HTTP 协议的前世今生,最后展望了一下 HTTP 协议的未来。这里面的每一个知识点都是值得深入学习的,比如 TCP 协议的慢启动、拥塞控制、快重传、快恢复,以这篇文章做起点,我会一点一点地耕耘出与协议栈的相关知识,下篇文章,着眼于 HTTP 协议安全部分的设计。