HTTP 协议
是浏览器和服务器之间的 通信语言
HTTP1 协议
HTTP/0.9: 图灵完备,但功能单一- 需求:主要用于学术交流,用来在网络之间
传递 HTML 超文本
的内容 - 特点:没有 HTTP 请求头和请求体,服务器也没有返回头信息
- 需求:支持多种类型的文件下载
- 通过请求头和响应头来进行协商文件的类型、压缩方式、编码等
- 特点:
- 新增 状态码:过响应行的方式来通知浏览器的
- 新增 Cache:缓存已经下载过的数据
- 新增 用户代理:收集客户端基础信息
- 缺点:
- 每一次 HTTP 通信都要经历:TCP连接 → 传输 HTTP 数据 → 断开 TCP
- 相当于每次和别人说一句话都要 say hello 一次,非常的搞笑
- 核心优化项:
- 持久连接
- 只要服务器或浏览器没有明确断开连接,TCP 连接会一直保持
- 默认开启,同一个域名最多同时建立 6 个 TCP 连接
- 使用 CDN 实现 域名分片 机制
- 将一个页面的资源利用多个域名下载,提高 TCP 并发数量
- 不成熟的 HTTP 管线化
- 持久连接虽能减少 TCP 重连次数,但 TCP 的连接还是串行的,如果有请求没有及时返回就会阻塞后面的请求,著名的 队头阻塞 问题
- 管线化是要解决队头阻塞的问题,但该方案由于种种原因被放弃
- 提供 虚拟机 的支持
- HTTP/1.0 中,每个域名绑定唯一 IP 地址,一个 IP 地址只能对应一个物理机,但随着虚拟机技术的发展,一个物理机可以有多个虚拟机,每个虚拟机都有自己的单独域名,但域名的 IP 是一样的
- 因此,新增了 Host 字段,来表示当前域名,服务器就可以根据 Host 做不同的处理
- 支持 动态生成内容
- HTTP/1.0 中,用
Content-Length
来确定数据的大小,但是随着服务端的发展,很多页面内容都是 动态生成 的,所以在传输之前不知道最终的数据大小,导致浏览器 无法确定 数据是否已全部接收 - Chunk transfer 机制:服务器会将数据分割成若干 任意大小 数据块且附加其长度,最后使用 零长度 的数据块作为发送完成标志
- HTTP/1.0 中,用
- 客户端 Cookie
- 解决 HTTP 无状态的限制,用于 标识 用户身份和信息
- 持久连接
- 依然存在的问题:
- 带宽的利用率却并不理想
- 带宽:每秒最大能发送或接收的字节数
- 上行带宽:每秒能 发送 的最大字节数
- 下行带宽:每秒能 接收 的最大字节数
- 原因:
- TCP 的 慢启动:
- TCP 建立连接之后就进入发送数据状态,发送数据的速度 由慢到快,慢启动是 TCP 为了减少 网络拥塞 的一种缓冲策略
- 页面中常用的一些关键资源文件本来就不大,如 HTML/CSS/JS 文件,通常这些文件在 TCP 建立连接后就要发起请求的,但由于是慢启动,耗时比正常时间要多很多,延迟了首次渲染页面的时长
- 资源竞争:
- 多条 TCP 连接会竞争固定带宽时无法区分重要资源的 优先级
- 当页面中下载的资源较多且带宽不够时,TCP 连接就会动态减慢接收数据的速度,而这个减慢没有优先级,也就会造成视频和图片这种较大的资源会和 HTML /CSS 这种渲染初始页面的 资源竞争 而造成白屏
- 队头堵塞:
- 每个 TCP 管道中同一时刻只能处理一个请求,请求未结束时,其他请求只能等待,类似于在同一个窗口排队办业务
- TCP 的 慢启动:
- 带宽:每秒最大能发送或接收的字节数
- 带宽的利用率却并不理想
解决 HTTP1.1 中 TCP 的慢启动、带宽资源竞争、队头拥塞问题,虽然 TCP 是造成这些问题的源头,但是目前依然无法脱离 TCP 协议,只能想办法规避上述问题。HTTP2 核心特性
- 如何解决队头堵塞?
- 多路复用机制
- 浏览器每个发起的请求都会携带一个
**ID**
,当服务器返回数据时也会携带对应的 ID,浏览器会将返回的 ID 的内容拼接为完整的 HTTP 响应数据
- 就好比去一个可以自助点餐的饭店,点完之后就等着上菜,解决了排队点菜造成的对头堵塞的问题
- 可将请求分成一帧一帧的数据进行传输,当收到优先级高的请求时,服务器可以暂停之前的请求来 处理优先级较高 的资源请求
- 实现机制:
HTTP2 新增了 二进制分帧层
- 浏览器准备好 请求数据
- 二进制分帧层将请求数据 转换 为一个个带有请求 ID 编号的帧,通过协议栈将其发送给服务器
- 服务器接收所有帧,会将所有 相同 ID 的帧 合并为一条完整的请求信息
- 服务器处理该请求,并将处理的响应行、响应头、响应体 分别发送 至二进制分帧层
- 二进制分帧层会将响应数据转换为一个个带有请求 ID 编号的帧,经过协议栈发送给浏览器
- 浏览器接收到响应帧后,会根据 ID 编号将帧的数据提交给对应的请求
flowchart BT subgraph HTTP2 协议栈 subgraph 请求列表 ... end subgraph 二进制分帧层 subgraph 完整请求 请求头+ID 响应头+ID 响应体+ID end end 请求列表 <-->二进制分帧层 <--> TLS[TLS 可选] <-->TCP/IP end
- 浏览器每个发起的请求都会携带一个
- 多路复用机制
- 如何解决 TCP 慢启动次数和 TCP 之间宽带资源竞争?
- 一个域名只使用一个 TCP 长连接 来传输数据,减少每次 TCP 连接造成的 副作用
- 可设置请求的优先级:优先加载重要资源
- 服务器推送
- 当刚请求 HTML 后,直接将 HTML 所需的 CSS/JS 也一块发送给浏览器,将于拿来这对首次打开页面的速度起来了 至关重要 的作用。
- 头部压缩
- TCP 传输层 的队头阻塞 :
- 虽然 HTTP2 解决了 应用层面到传输层 的队头阻塞问题,但是 传输层到网络层 的丢包重传机制还是可以堵塞 TCP 管道,而 TCP 最初就是为了单连接而设计的
- 在丢包严重的情况下 HTTP2 比 HTTP1.1 表现还差,因为后者有 6 个 TCP 管道
- TCP 建立连接的延时:
- 在传输数据之前,需要花费 TCP + TLS 握手所消耗的 3~4 RTT
- TCP 协议僵化:
- 因 TCP 发展到现在的历史包袱已经太重,而又属于计算机相对的底层和核心的位置,全设备同步是不可能的
甩掉 TCP、TLS 的包袱,构建高效网络QUIC 协议
在考虑兼容中间设备的僵化,重新构建一个新的 传输层协议 并被很好兼容,已无可能,只能在现有基础上做拓展和优化。
【HTTP 的前世今生】因为 HTTP3 选择折中的方案 — UDP 协议,基于 UDP 实现了类似于 TCP 的功能,这套协议称作为 QUIC 协议。
文章图片
HTTP/2 和 HTTP/3 协议栈
HTTP3 的挑战
- 兼容性:服务器和浏览器都没有对 HTTP3 提供比较完整的支持
- UDP 的市场成熟度:系统内核对 UDP 的优化远远没有达到 TCP 的优化程度
- 中间设备僵化:其对 UDP 的优化程度低于 TCP,使用 QUIC协议时, 3%~7% 的丢包率
核心诉求 | 优点 | 不足 | |
---|---|---|---|
HTTP 0.9 | 能传输 HTML 文件,用于学术交流 | 简单、图灵完备 | 功能单一 |
HTTP 1.0 | 能下载多种文件类型 | 完成时代迫切下载需求 | TCP 重复握手,效率低下 |
HTTP 1.1 | TCP 持久话复用 | 优化 1.0 各种需求 | 管道阻塞 |
HTTP 2.0 | 实现管道内多路复用 | 大幅提升 1.1 的传输效率 | TCP 协议导致的各种问题 |
HTTP 3.0-未来 | 解决 TCP 的短板 | 更快速 | 兼容性差 |