温馨提示
该文章距离上次更新已经过去了 1284 天,文章内容可能已经过时。
HTTP是什么
HTTP(Hyper Text Transfer Protocol)超文本传输协议,它是从WEB服务器传输超文本标记语言(HTML)到本地浏览器的传送协议,是互联网上应用最为广泛的一种网络协议。
HTTP最初的目的是为了提供一种发布和接收HTML页面的方法,现在有多个版本,其中最广泛使用的是HTTP/1.1版本。
HTTP/0.9
HTTP/0.9在1990年问世,是第一个版本的HTTP协议,已过时。它的组成极其简单,只允许客户端发送GET这一种请求,且不支持请求头。由于没有协议头,造成了HTTP/0.9协议只支持一种内容,即纯文本。不过网页仍然支持用HTML语言格式化,同时无法插入图片。由于不支持POST请求,因此客户端无法向服务端发送太多的信息。
<html>
<body>Hello World</body>
</html>
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
HTTP/0.9具有典型的无状态性,每个事务独立进行处理,事务结束时就释放这个连接。由此可见,HTTP协议的无状态特点在其第一个版本0.9中已经成型。一次HTTP/0.9的传输首先要建立一个由客户端到Web服务器的TCP连接,由客户端发起一个请求,然后由Web服务器返回页面内容,然后连接会关闭。如果请求的页面不存在,也不会返回任何错误码。
HTTP/1.0
HTTP/1.0最早在网页中的使用是在1996年,是HTTP协议的第二个版本,且是第一个在通讯中指定版本号的HTTP协议版本(HTTP/0.9是后来为了区别其它的版本号才定位在0.9的),它和HTTP/0.9版本主要有以下的几个区别:
- HTTP/0.9只支持GET请求,而HTTP/1.0新增加了POST和HEAD请求。(HEAD请求只会返回响应头)
- 任何格式的数据都可以被发送,不仅局限于文字,响应对象不止局限于超文本
- 响应对象以一个响应状态行开始
响应状态行一般包括3个信息:1.协议版本 2.状态码(表示请求成功或失败。例如200、404) 3.状态文本(用于描述状态码,帮助人们理解该HTTP消息。例如Not Found、OK)
响应状态码是Web服务器用来告诉客户端,当前的网页的请求发生了什么
例如:HTTP/1.1 200 OK
- 除了数据部分,支持请求头和响应头(Headers),用来描述一些元数据
- 支持长连接,但默认还是使用短连接,也就是每次请求都需要建立一次连接(三次握手)这也是HTTP/1.0的缺陷
HTTP/1.1
HTTP/1.1是HTTP协议的第三个版本,是在1999年才开始广泛应用于现在的各大浏览器网络请求中,同时HTTP1.1也是当前使用最为广泛的HTTP协议。 它和HTTP/1.0版本主要有以下的几个区别:
- 持久连接,HTTP/1.1支持长连接(PersistentConnection),在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection:keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。keep-alive保持连接时间的长短是可以配置的,它是由Web服务器决定的,例如可以配置一个连接可以发起多少条请求,或者一个连接的保持时间。
- 请求流水线,HTTP/1.1支持请求流水线(Pipelining)处理,在以前,一个TCP连接中,客户端发送完A请求后,需要等待服务端响应且收到了服务端的响应后才会去发送B请求,请求流水线可以让客户端在一个TCP连接中,同时发送多个请求,服务端接收到请求后会依次就行回应,这样加快了HTTP协议的效率。
- 错误响应码,HTTP/1.1中新增了24个错误状态响应码
- 缓存处理,HTTP/1.1新增了更多的缓存控制策略,如 Entity tag、If-Unmodified-Since、If-Match、If-None-Match 等;
- 新增了多个请求方式,例如:PUT、DELETE、PATCH、OPTIONS、DELETE
- 请求头中新增了host字段,提供了虚拟主机的功能
- 请求头中新增了range头域,在HTTP/1.0中存在一些带宽浪费现象,例如:客户端需要对象中的某一部分,服务端也会将整个对象返回,range允许只返回资源的某一个部分(返回码206),这样充分利用了带宽,这是断点续传的基础。
HTTP/1.1的缺点
- HTTP/1.1虽然允许TCP连接复用,但是服务端在处理所有的请求时候都是按次序来的,如果前面的请求处理时间过长,后端的所有请求都要排队等待这,这就是“线头堵塞”。为了避免这个问题,可以减少请求的次数,或者同时开始多个持久连接。比如:文件的合并打包、域名的分片等。
- 单向请求,请求只能由客户端发起
- Header数据传输量和冗余量大,请求头Header会固定携带Cookie、User Agent等固定字段,多达几百字节甚至上千字节,且它们不能像内容Body一样被压缩,Body经常只有几十个字节,且通常会经过gzip压缩,或者传输的本身就是压缩过后的二进制文件(图片、音频),更要命的是每次的请求都会携带这些固定字段,而每次这些固定字段的信息都非常相似,这在一定程度上增加了传输的成本。
- 明文传输,HTTP/1.1在传输数据时,所有传输的内容都是明文传输,客户端和服务器都无法验证对方的身份,这在一定程度上无法保证数据的安全性。
HTTP/2.0
HTTP/2.0是HTTP的第二个主要版本,HTTP/2.0是HTTP协议自1999年HTTP/1.1发布后的首个更新,主要基于SPDY协议。
HTTP/2.0的特点是:在不改动HTTP语义、方法、状态码、URI及首部字段的情况下,却能致力于突破上一代标准的性能限制,改进传输性能,实现低延迟和高吞吐量。
HTTP/2.0与HTTP/1.1版本主要有以下几个区别:
- 二进制分帧传输,在HTTP/1.x中,数据都是通过文本的方式传输,文本的传输方式有很多缺陷,文本的表现形式有多样性,所以要做到健壮性要考虑很多场景。而二进制只有0和1,所以使用二进制传输,方便且健壮。
为了保证HTTP不受影响,就需要在应用层和传输层之间增加一个二进制分帧层,HTTP会将所有传输的信息分为更小的帧(帧是新协议通信的最小单位)和流(由一个或多个帧组成),并用二进制编码,Http/2.0给每个http的request都分配唯一的streamId,而每个request切割出来的fram都共用这个streamId,这样的话Http/2.0就可以基于这个streamid将切割的信息还原(简单来说就是流中的帧对数据进行了标识),其中首部消息会被封装到Headers帧中,Request Body则封装到Data帧中,分帧之后Header和Body的报文结构就完全消失了,协议只看得到一个个’碎片’。
HTTP/2.0中,同域名下所有通信都在单个链接中完成,同一链接上有多个不同方向的数据流在传输,每条数据流都以消息的形式发送,而消息又由一个或多个帧组成。客户端可以一边乱序发送stream,也可以一边接收着服务器的响应,而服务器那端同理。
2.链路复用,在HTTP/1.1中,Pipelining和启动多个TCP连接虽然实现了多个http并发的问题,但是服务端在处理的时候是阻塞的,只能一个请求一个请求处理。
多路复用就是在一个 TCP 连接中可以存在多条流。换句话说,也就是可以发送多个请求,且请求不分先后,服务端可以同时处理。这样整个页面的请求只需要一次慢启动,同时避免了多个TCP连接竞争带宽所带来的问题。通过这个技术,避免了HTTP/1.1版本中的线头阻塞问题,极大的提高传输性能。
HTTP/2.0中由于单个链接可以承载不任意数量的的双向流数据,所以通过资源合并减少请求次数,以及域名分片等优化手段,对于HTTP/2.0是没有效果的。 - 头部Header压缩,HTTP/2.0使用了HPACK(HTTP2头部压缩算法)压缩格式对传输的Header进行编码,减少了Header的大小,可以达到50%-90%的高压缩率。并在两端维护了索引表,用于记录出现过的Header中的键值对,后面在传输过程中对于相同的数据,不再通过每次请求和响应发送,对端就可以通过键名找到对应的值,对于新的头部键值对要么被加在索引表的末尾,要么替换表中之前的值。
- 服务端推送,在HTTP/2.0中,服务端推送是唯一一个需要用户自己配置的,服务端可以在客户端某个请求后,主动推送其它资源。例如某些用户一定会请求的资源(用户请求了index.html,包含在index.html中的index.css用户是一定会去请求的),可以提前推送给客户端,可以相对减少延迟时间。
- 请求优先级,在HTTP/2.0中,每个请求中都可以带一个31bit的优先值,0表示最高优先值,数值越大,优先级越低,浏览器可以在发现资源时立即分派请求,指定每个流的优先级,让服务器决定最优的响应次序。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。
- 更加安全,HTTP/2.0使用了TLS的拓展ALPN做为协议升级,除此之外,HTTP/2.0对TLS的安全性做了近一步加强,通过黑名单机制禁用了几百种不再安全的加密算法。
HTTP/2.0的缺点
- HTTP/2都是使用TCP协议来传输的,而如果使用HTTPS的话,还需要使用TLS协议进行安全传输,而使用TLS也需要一个握手过程,这样就需要有两个握手延迟过程:
- 在建立TCP连接的时候,需要和服务器进行三次握手来确认连接成功,也就是说需要在消耗完1.5个RTT之后才能进行数据传输。
- 进行TLS连接,TLS有两个版本——TLS1.2和TLS1.3,每个版本建立连接所花的时间不同,大致是需要1~2个RTT。
总之,在传输数据之前,我们需要花掉 3~4 个 RTT。
- 在HTTP/2.0中,多个请求是跑在一个TCP管道中的。但当出现了丢包时,HTTP/2.0的表现反倒不如HTTP/1.1了。因为TCP为了保证可靠传输,有个特别的“丢包重传”机制,丢失的包必须要等待重新传输确认,HTTP/2.0出现丢包时,整个 TCP 都要开始等待重传,那么就会阻塞该TCP连接中的所有请求。而对于 HTTP/1.1来说,可以开启多个 TCP 连接,出现这种情况反到只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。
HTTP/3.0
Google 在推SPDY的时候就已经意识到了这些问题,于是就另起炉灶搞了一个基于 UDP 协议的“QUIC”协议,让HTTP跑在QUIC上而不是TCP上。而这个“HTTP over QUIC”就是HTTP协议的下一个大版本,HTTP/3.0。它在HTTP/2.0的基础上又实现了质的飞跃,真正“完美”地解决了“队头阻塞”问题。
QUIC新功能
上面我们提到QUIC基于UDP,而UDP是“无连接”的,根本就不需要“握手”和“挥手”,所以就比TCP来得快。此外QUIC也实现了可靠传输,保证数据一定能够抵达目的地。它还引入了类似HTTP/2的“流”和“多路复用”,单个“流"是有序的,可能会因为丢包而阻塞,但其他“流”不会受到影响。具体来说QUIC协议有以下特点:
- 实现了类似TCP的流量控制、传输可靠性的功能。
虽然UDP不提供可靠性的传输,但QUIC在UDP的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些TCP中存在的特性。 - 实现了快速握手功能。
由于QUIC是基于UDP的,所以QUIC可以实现使用0-RTT或者1-RTT来建立连接,这意味着QUIC可以用最快的速度来发送和接收数据,这样可以大大提升首次打开页面的速度。0RTT 建连可以说是 QUIC 相比 HTTP2 最大的性能优势。 - 集成了TLS加密功能。
目前QUIC使用的是TLS1.3,相较于早期版本TLS1.3有更多的优点,其中最重要的一点是减少了握手所花费的RTT个数。 - 多路复用,彻底解决TCP中队头阻塞的问题
和TCP不同,QUIC实现了在同一物理连接上可以有多个独立的逻辑数据流(如下图)。实现了数据流的单独传输,就解决了TCP中队头阻塞的问题。