http发展史
# http0.9
特点: 极其简单,只有一个方法 get,请求和相应内容都精简到了极致
缺点:
- 只有一个方法 get,功能局限
- 服务器只能返回 html 格式的字符串,不支持其他格式
# http1.0
特点:
- 任何格式的内容都可以传输,如文字、传输图像、视频、二进制文件等
- 引入了 post、head 方法,丰富了浏览器和服务器的互动手段
- 引入了 http header,用来描述一些元数据。新增状态码、多字符集支持、多部分发送、权限、缓存、内容编码等功能
缺点:
- 每个 tcp 连接只能发送一个请求。发送完毕后,连接就关闭,如果还要请求其他资源,就必须在新建一个连接
- tcp 连接的新建成本很高,因为需要客户端和服务端三次握手,并且开始发送速率较慢。所以 http1.0 版本的性能比较差。随着网页加载的外部资源越来越多,这个问题越来越突出。
优化策略:
为了解决这个问题,有些浏览器在请求时,用了一个非标准的 connection 字段。connection:keep-alive 这个字段要求服务器不要关闭 tcp 连接,以便其他请求复用。服务器同样回应这个字段。connection:keep-alive 一个可以服用的 tcp 连接就建立了,指导客户端或者服务端主动关闭连接。
缺陷:connection 不是标准字段,不同实现的行为可能不一致
# http1.1
特点:
- 持久连接。
在 http1.0 以前,每进行一个 http 通信都要断开一次 tcp 连接。比如使用浏览器浏览一个包含多张图片的 html 页面时,在发送请求访问 html 页面资源的同时,也会请求该 html 页面里面包含的其他资源。因此,每次的请求都会造成很多的 tcp 连接建立和断开,增加通信量的开销
为了解决连接问题,http1.0 增加了持久连接的方法。其特点是,只要任意一段没有明确提出要断开连接,就保持 tcp 连接状态。旨在建立一次 tcp 连接后进行多次请求和相应的交互。在 http1.1 中,所有的连接默认都是持久连接
- 管线化
持久连接使用多次请求以管线化方式发送成为可能。以前发送请求后需等待并收到相应,才能发送下一个请求。管线化基础出现以后,不用等待就可以发送下一个请求。这样就可以同时进行发送多个请求,而不需要一个接一个得等待响应了。
比如,当请求一个包含多张图片的 html 页面时,与挨个连接相比,用持久连接可以让请求更快结束。而管线化技术要比持久连接速度更快。请求数越多,时间差就越大
- 分块编码
分块编码是一种传输编码,是报文的属性。http1.1 的传输编码方式仅对分块传输编码有效。分块编码把报文分割成若干个已知大小的块。块之间是紧挨着发送的,这样就不需要再发送之前知道整个报文的大小了。
起因:
若客户端与服务端不是持久连接,客户端就不需要知道他在读取的主题的长度,而只需要读取到服务器关闭连接为止。
当使用持久连接时,在服务器写主体之前,必须知道他的大小并在 content-length 首部中发送。如果服务器动态创建内容,就可能在发送之前无法知道主体的长度
优势:分块编码为上述困难提供了解决方案,只要允许服务器把主体分块发送,说明每块的大小就可以了。因为主体是动态创建的,服务器可以缓存他的一部分,发送其大小和相应的块,然后在主体发送完之前重复这个过程。服务器可以用大小为 0 的块作为主体结束的信号,这样就可以继续保持连接,为下一个相应做准备。
- 更多功能
http1.1 定义了五种方法 options、put、delete、trace、connect
新增了 host 字段,用来指定服务器的域名。有了 host 字段,就可以将请求发往同一台服务器上的不同网站,为虚拟机的兴起打下了基础
缺点:
- 过于庞大
- 过多的可选项
- 未能被充分利用的 tcp
- 延迟
- 线头阻塞
优化策略:
- spriting 图片精灵
- 内联 就是 base64
- 拼接 就是把几个 js 合并成一个
- 分片 就是把你的服务分散在尽可能多的主机上
- 限制请求头
# http2.0
特点:
- 二进制帧层
- 多路复用
- 优先级和依赖性
- 头部压缩
- 重置
http1.1 有一个缺点是:当一个含有确切纸的 connect-length 的 http 消息被发送之后,你就很难中断他了。当然,可以断开整个 tcp 连接,但是需要重新建立三次握手
一个更好的方案就是至终止当前传输的消息并重新发送一个新的。在 http2 里面,我们可以通过发送RST-STREAM
帧来实现
- 服务器推送
也叫缓存推送。当一个客户端请求资源 X,而服务器知道他很可能需要资源 Z 的情况下,服务器可以再发送请求之前,就主动推送资源 Z 给客户端
- 流量控制
- 单连接
一个域名只需要一个连接,所有通信都通过多路复用实现
缺陷:
tcp 对头阻塞
http2 是基于 tcp 实现的。相比之前的版本,http2 的 tcp 连接次数少了很多。
采用 http2 时,浏览器一般会在单个 tcp 连接中创建并行的几十个乃至上百个传输
如果采用 http2 连接双方中的网络中有一个数据包丢失,或者任何一方的网络出现中断,整个 tcp 连接就会暂停,丢失的数据包需要被重新传输。因为 tcp 是一个按需传输的链条,因此如果其中一个点丢失了,链路上之后的内容就需要等待
单个数据包造成的阻塞,就是 tcp 的对头阻塞
随着丢包率的增加,http2 的表现越来越差。在 2%的丢包率中,测试结果表明 http1 用户性能更好,因为 http1 一般有六个 tcp 连接,哪怕一个连接阻塞了,其他没有丢包的连接仍然可以继续传输
# http3.0
就是基于 QUIC 的 http2.0
特点:
- 安全性
QUIC 协议没有明文的版本,必须使用 TLS 建立加密连接,加密可以避免协议僵化等拦截和特殊处理。
QUIC 只在加密协议协商时会发送几个明文传输的初始握手报文
- 减少延迟
与 tcp 三次握手相比,QUIC 提供了 0-RTT 和 1-RTT 的握手,减少了协商和建立新连接时所需的时间
除此之外,QUIC 提供了提早传输更多数据的早期数据特性,并且它的使用比 tcp 快速打开更加便捷
因为数据流概念的引入,客户端不用等待前一个连接结束,便可以与同一个主机建立另一个逻辑连接
- 有序交付
- 快速握手
- 基于 UDP
# http3 对比 http2 的优势
得益于 QUIC 的 0-RTT 握手,http3 可以提供更好的早期数据支持,而 tcp 快速打开和 tls 同城只能传输更少的数据,且经常存在问题
得益于 QUIC,http3 的握手速度比 tcp+tls 快得多
http3 不存在明文的不安全版本。尽管在互联网上很少见,HTTP2 还是可以不配合 https 来实现和使用
通过 ALPN 扩展,HTTP2 可以直接在 TLS 握手时进行协商。HTTP3 基于 QUIC,所以需要凭借相应中的 Alt-Svc 来向客户端宣告
# http 1.0/1.1/2.0 在并请求上的主要区别
# http/1.0
每次 tcp 连接都只能发送一个请求,当服务器响应后就会关闭此次连接,再次在发送请求还需要再次建立 tcp 连接
# http/1.1
默认采用持续连接,tcp 连接默认不关闭,可以被多个请求复用,不用显式的生命 keep-alive
增加了管道机制,在同一个 tcp 链接里,允许多个请求同时发送,增加了一定的并发性
同一个 tcp 链接里,所有的数据通信是按顺序进行的,如果服务器响应慢,会有很多的请求在排队,造成对头阻塞
# http/2.0
加了双工模式,客户端可以同时发送多个请求,服务器也可以同时相应多个请求,解决了 http 的对头阻塞问题
使用了多路复用,同一个 tcp 连接可以并发处理多个请求
服务器可以主动向客户端发起数据。
# http/1.1 长连接和 http/2.0 多路复用的区别
http/1.1 同一时间一个 tcp 连接只能处理一个请求,采用一问一答的形式,上一个请求响应后才能处理下一个请求
由于浏览器最大连接数的限制,所以才有了最大请求数的限制
http/2.0 同域名下的所有通信都在单个连接上完成
# 为什么 http/1.1 无法实现多路复用
数据传输格式的问题
http/1.1 基于文本分割解析的协议
http/2.0 基于二进制帧的协议