本篇文章参考以下博文
阅读本篇文章前,可以先了解一下客户端如何与服务端建立连接
文章目录
HTTP各个版本区别
发布时间 | 协议 | 命令(新增) | 请求格式 | 特点 | 缺点 | |
---|---|---|---|---|---|---|
HTTP 1.0 | 1996.05 | TCP/IP | GET、POST、HEAD | 头文件是文本,数据体是本文或二进制 | 请求与回应格式改变,通信必须包含HTTP header,其他功能有状态码,权限,缓存、内容编码等 | 每个TCP连接只能发送一个请求。 发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接,建立连接成本太高,发送速率较慢 |
HTTP 1.1 | 1997.01 | TCP/IP | PUT、PATCH、OPTIONS、DELETE | 同上 | 管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求。 | “队头堵塞”(Head-of-line blocking)所有数据通信都是按次序进行的,上一个结束,下一个才能开始 |
HTTP 2 | 2015 | TCP/IP | 同上 | 纯二进制 | HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。数据帧以乱序发送,不用再排队等待发送了 | 如果产生丢包,TCP连接就需要重新建立,造成后面数据阻塞 |
QUIC(HTTP3.0) | 2016.11 | UDP/IP | - | 同上 | 0-RTT 建连,多路复用 | - |
HTTP1.0
1.请求格式
GET / HTTP/1.0
User-Agent: Mozilla/5.0(Macintosh; Intel Mac OS X 10_10_5)
Accept: */*
2.响应格式
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 125742
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84
<html>
<body>Hello World!</body>
</html>
回应格式“头信息 + 空行 + 数据”
第一行是“协议版本 + 状态码 + 状态描述”
3.Content-Type
由于 HTTP 1.0 规定,头信息必须是 ASCII 码,后面数据的格式可以任意,所以必须规定,发送的数据的格式是什么,这就是 Content-Type的作用。下面是 Content-Type的一些常见值
- text/plain
- text/html
- text/css
- image/jpeg
- image/png
- application/javascript
4.缺点
- 一次连接只能发送一个请求,效率太慢
部分浏览器在请求时,会添加一个非标准字段 Connection 字段
Connection: keep-alive
HTTP1.1
1.持久连接
引入持久连接,不用再声明 Connection 了,客户端可以在最后一个请求中添加 Connection: close 明确关闭 TCP 连接
2.管道机制
在同一个 TCP 连接中,可以同时发送多个请求,服务端按顺序先回应 A,再回应 B 。
3.Content-Length 字段
声明本次数据长度,用来区分返回的数据包属于哪一次回应。
4.分块传输编码
头信息中需要添加 Transfer-Encoding: chunked 可以不等待所有操作完成,就发送数据,不使用 Content-Length 字段
Transfer-Encoding: chunked
5.缺点
① 所有数据通信是按次序进行的,服务器只有处理完一个请求后,才能处理下一个,回复就比较慢,会造成“队头堵塞”。
为解决这个问题,催生出多种网页优化技巧(1.减少请求数,2.同时多开持久连接)。
- 将图片嵌入css代码
- 域名分片
- 精灵图
- 拼接,将多个小体积JavaScript通过Webpack等打包成一个大体积的文件(如果一个文件修改就会导致多个文件重新下载)
② 无状态特性带来巨大的HTTP头,报文Header一般会携带"User Agent"“Cookie”“Accept”"Server"等许多固定的头字段,很多内容存在重复,造成了大量资源浪费。
③ 明文传输,安全性不高。所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份,这在一定程度上无法保证数据的安全性。
HTTP2
SPDY 协议为 HTTP2 奠定基础,改造了 HTTP协议 本身
数据交互进完全二进制时代,头信息帧与数据帧,方便定义额外的帧。
1.多工解决“队头堵塞”
原理是在一个 TCP 连接中,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。
2.数据流
由于 HTTP2 的数据不是按顺序发送的,为了保证记录每一个请求对应的相应数据,必须对数据进行标记
HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。
客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。
3.压缩头部
对于某些相同的数据,可以进行压缩,只存指针。
- 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送;
- 首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
- 每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值
4.多路复用
- 域名下所有通信都在单个连接上完成。
- 单个连接可以承载任意数量的双向数据流。
- 数据流以消息形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。
上面的特性使传输性能有了质的提升:
- 同个域名只需要占用一个 TCP 连接,使用一个连接并行发送多个请求和响应,这样整个页面资源的下载过程只需要一次慢启动,同时也避免了多个TCP连接竞争带宽所带来的问题。
- 并行交错地发送多个请求/响应,请求/响应之间互不影响。
- 在HTTP/2中,每个请求都可以带一个31bit的优先值,0表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。
5.Server Push
类似 websocket ,服务器可以主动发送消息给客户端,主动推送遵守同源策略,换句话说,服务器不能随便将第三方资源推送给客户端,而必须是经过双方确认才行。
6.安全性增强
由于主流的浏览器都只支持加密的 HTTP/2 ,也就是说互联网上的 HTTP/2 都是使用 HTTPS 协议名,跑在 TLS 上面。
QUIC(HTTP3.0)
HTTP/2 并不完美,主要是因为 底层支撑的TCP协议造成的 。
1.HTTP/2 缺点
①TCP 以及 TCP + TLS建立连接的延时
HTTP/2都是使用 TCP 协议来传输的,如果使用 HTTPS 的话,还需要使用 TLS 进行安全传输,使用 TLS 也需要一个握手过程,这样就需要两个握手过程 。
- 在建立TCP连接的时候,需要和服务器进行三次握手来确认连接成功,也就是说需要在消耗完1.5个RTT之后才能进行数据传输。
- 进行TLS连接,TLS有两个版本——TLS1.2和TLS1.3,每个版本建立连接所花的时间不同,大致是需要1~2个RTT。
从上面看,建立 HTTP/2 基本要求消耗 3-4个 RTT。
②TCP 的队头堵塞没有彻底解决
由于 HTTP/2 是多个请求跑在一个 TCP 中,当出现丢包情况的时候,TCP 为了保证可靠传输,会进行“丢包重传”,这就导致了其中一个请求丢包,整个 TCP 重新传包,阻塞了其他请求。这使得 HTTP/2 的性能反而不如 HTTP/1.1 了。
HTTP/3介绍
完美解决“队头阻塞”,一个基于 UDP 协议的“QUIC”协议。
QUIC 新功能
QUIC 基于 UDP。UDP 又是“无连接”的,这就使得 HTTP/3 不需要“握手” 和 “挥手”,所以可以去省去 3个 RTT (握手1.5 + 挥手 2)。为了保证数据一定能够到达,还引入了“流” 和 “多路复用”。
- 实现了 TCP 的流量控制和传输可靠性。
- 实现快速握手
由于基于 UDP ,QUIC 可以实现 0-RTT 或 1-RTT 来建立连接,0-RTT 是相比于 HTTP/2 最大的性能优势。
- 继承了 TLS 的加密功能,减少握手花费的 RTT 个数。
- 多路复用,完美解决 TCP 队头阻塞问题。