特点:- 无连接:每次请求都需要建立新的 TCP 连接,请求完成后立即关闭 - 无状态:服务器不保存客户端的状态信息 - 简单:协议相对简单,功能有限 - 只支持 GET、POST、HEAD 方法
存在的问题:- 频繁建立/关闭连接,性能开销大。- 无法复用连接 - 完全串行,有队头阻塞问题
主要改进:
持久连接 (Keep-Alive)
Connection: keep-alive管道化
新增了一些请求方法
缓存机制
Cache-Control: max-age-3600 控制缓存事件
ETag: '*****' 资源变化验证
If-None-Match: '*****'分块传输编码
Transfer-Encoding: chunked仍然存在的问题:
二进制分帧
多路复用
没有彻底解决,因为 TCP 有一个重要的特征:按序交付。
HTTP2.0 可能会发生这样的情况:
发送端发送 TCP 数据包:
包1 [seq=100] ──► 成功到达
包2 [seq=200] ──► 丢失 ❌
包3 [seq=300] ──► 成功到达
包4 [seq=400] ──► 成功到达
接收端的处理:
✓ 包1:交付给应用层(HTTP/2.0)
✗ 包2:丢失,等待重传
✓ 包3:已收到,但必须等待包2
✓ 包4:已收到,但必须等待包2
↓
即使包3、包4已经到达,TCP 也不会交付给应用层
必须等待包2重传成功后,才能按顺序交付 2、3、4
一个包的丢失会阻塞整个连接上的所有流。头部压缩
服务器推送
流优先级
虽然 UDP 没有内置的可靠性保证,所以 QUIC 自己实现一套基于流级别的可靠性传输逻辑。
Stream 1 的数据包 ──► 独立确认、独立重传
Stream 2 的数据包 ──► 独立确认、独立重传
Stream 3 的数据包 ──► 独立确认、独立重传
如果 Stream2 的某个包丢失:
Stream1 不受影响,正常交付。
Stream 2 只阻塞自己,等待重传。
Stream 3: 不受影响,正常交付HTTP 3.0 是怎么解决 HTTP 2.0 的队头阻塞问题的?
HTTP 2.0 是基于 TCP 的,TCP协议是字节流协议,它要求“按顺序交付”,如果中间某个包丢了,后面的包即使收到了,TCP 也不会交给上层应用,必须等丢失的包重传,补上。
虽然 HTTP 2.0 在应用层实现了多路复用(一个 TCP 连接上跑多个流),但是只要底层的 TCP 有丢包,所有的流都被阻塞,这就是应用层看到的“队头阻塞”。
HTTP 3.0 不再基于 TCP, 而是基于 QUIC (UDP 之上实现的传输层协议) QUIC 自己实现了可靠的传输、流量控制、加密(基于 TLS 1.3), 但和 TCP 有以下不同点:- 每个流的数据包都独立确认、独立重传。- 某个流丢包的时候,只阻塞这个流,其他流不受影响。
为什么实际工程中,使用 SSE 时,使用 http1.1 比 http2.0 好