WEB服务-HTTP协议介绍
HTTP协议介绍
什么是HTTP?
超文本传输协议,是一个基于请求与响应,无状态的,应用层的协议,常基于TCP/IP协议传输数据,互联网上应用最为广泛的一种网络协议,所有的WWW文件都必须遵守这个标准。设计HTTP的初衷是为了提供一种发布和接收HTML页面的方法。
版本 | 产生时间 | 内容 | 发展现状 |
---|---|---|---|
HTTP/0.9 | 1991年 | 不涉及数据包传输,规定客户端和服务器之间通信格式,只能GET请求 | 没有作为正式的标准 |
HTTP/1.0 | 1996年 | 传输内容格式不限制,增加PUT、PATCH、HEAD、 OPTIONS、DELETE命令 | 正式作为标准 |
HTTP/1.1 | 1997年 | 持久连接(长连接)、节约带宽、HOST域、管道机制、分块传输编码 | 2015年前使用最广泛 |
HTTP/2 | 2015年 | 多路复用、服务器推送、头信息压缩、二进制协议等 | 逐渐覆盖市场 |
http/0.9
http/0.9:1991年,原型版本,功能简陋,只有一个命令GET。GET /index.html ,服务器只能回应HTML格式字符串,不能回应别的格式。
http/1.0
http/1.0:1996年5月,支持cache, MIME, method
- 每个TCP连接只能发送一个请求,发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接
- 引入了POST命令和HEAD命令
- 头信息是 ASCII 码,后面数据可为任何格式。服务器回应时会告诉客户端,数据是什么格式,即Content-Type字段的作用。这些数据类型总称为MIME 多用途互联网邮件扩展,每个值包括一级类型和二级类型,预定义的类型,也可自定义类型, 常见Content-Type值:text/xml,image/jpeg,audio/mp3
http/1.1
http/1.1:1997年1月(主流1.1)
- 引入了持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive。对于同一个域名,大多数浏览器允许同时建立6个持久连接
- 引入了管道机制(pipelining),即在同一个TCP连接里,客户端可以同时发送多个请求,进一步改进了HTTP协议的效率
- 新增方法:PUT、PATCH、OPTIONS、DELETE
- 同一个TCP连接里,所有的数据通信是按次序进行的。服务器只能顺序处理回应,前面的回应慢,会有许多请求排队,造成"队头堵塞"(Head-of-line blocking)
- 为避免上述问题,两种方法:一是减少请求数,二是同时多开持久连接。网页优化技巧,如合并脚本和样式表、将图片嵌入CSS代码、域名分片(domain sharding)等
- HTTP 协议不带有状态,每次请求都必须附上所有信息。请求的很多字段都是重复的,浪费带宽,影响速度
HTTP1.0和HTTP1.1的区别
- 缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标 准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略
- 带宽优化及网络连接的使用,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某 个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在 请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content), 方便了开发者自由的选择以便于充分利用带宽和连接
- 错误通知的管理,在HTTP1.1中新增24个状态响应码,如409(Conflict)表示请求的资源与资 源当前状态冲突;410(Gone)表示服务器上的某个资源被永久性的删除
- Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的 URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以 存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请 求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)
- 长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理, 在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在 HTTP1.1中默认开启Connection: keep-alive,弥补了HTTP1.0每次请求都要创建连接的缺点
HTTP/1.1 的缺陷
- 高延迟 – 带来页面加载速度的降低
网络延迟问题主要由于队头阻塞 (Head-Of-Line Blocking) 产生,导致带宽无法被充分利用。
队头阻塞是指,当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一并被阻塞,会导致客户端迟迟收不到数据。针对队头阻塞, 人们尝试过以下办法来解决:
- 将同一页面的资源分散到不同域名下,提升连接上限。Chrome 有个机制,对于同一个域名,默认允许同时建立 6 个 TCP 持久连接。使用持久连接时,虽然能共用一个 TCP 管道,但是在一个管道中同一时刻只能处理一个请求,在当前的请求没有结束之前,其他的请求只能处于阻塞状态。另外,如果在同一个域名下同时有 10 个请求发生,那么其中 4 个请求会进入排队等待状态,直至进行中的请求完成。
- Spriting 合并多张小图为一张大图, 再用 JavaScript 或者 CSS 将小图重新“切割”出来的技术。
- 内联 (Inlining) 是另一种防止发送很多小图请求的技巧,将图片的原始数据嵌入在 CSS 文件里面的 URL 里,减少网络请求次数。
.icon1 {
background: url(data:image/png;base64,<data>) no-repeat;
}
.icon2 {
background: url(data:image/png;base64,<data>) no-repeat;
}
- 拼接 (Concatenation) 将多个体积较小的 JavaScript 使用 webpack 等工具打包成 1 个体积更大的 JavaScript 文件, 但如果其中 1 个文件改动,会导致大量数据被重新下载多个文件。
- 无状态特性 – 带来巨大的 HTTP 头部
由于报文 Header 一般会携带"User Agent" “Cookie”“Accept”"Server"等许多固定的头字段,多达几百字节甚至上千字节,但 Body 却经常只有几十字节(比如 GET 请求、 204/301/304 响应),成了不折不扣的“大头儿子”。Header 里携带的内容过大,在一定程度上增加了传输成本。并且成千上万的请求响应报文里有很多字段值都是重复的,非常浪费。
- 明文传输 – 带来不安全性
HTTP/1.1 在传输数据时,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份,这在一定程度上无法保证数据的安全性。
- 不支持服务器推送消息
HTTPS
HTTPS:1994年
什么是HTTPS?
HTTPS是身披SSL/TLS外壳的HTTP。
HTTPS是一种通过计算机网络进行安全通信的传输协议,经由HTTP进行通信,利用SSL/TLS建立全信道,加密数据包。HTTPS使用的主要目的是提供对网站服务器的身份认证,同时保护交换数据的隐私与完整性。
PS:TLS是传输层加密协议,前身是SSL协议,由网景公司1995年发布,有时候两者不区分。
HTTPS工作方式:
先工作在HTTP1上,通过HTTP1传递交换得到秘钥,然后切换到HTTPS上工作。
优点
- 使用 HTTPS 协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
- HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 HTTP 协议安全,可防止数据在传输过程中被窃取、改变,确保数据的完整性。
- HTTPS 是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。
缺点
- 相同网络环境下,HTTPS 协议会使页面的加载时间延长近 50%,增加 10%到 20%的耗电。此外,HTTPS 协议还会影响缓存,增加数据开销和功耗。
- HTTPS 协议的安全是有范围的,在黑客攻击、拒绝服务攻击和服务器劫持等方面几乎起不到什么作用 [2] 。
- 最关键的是,SSL 证书的信用链体系并不安全。特别是在某些国家可以控制 CA根证书的情况下,中间人攻击一样可行。
- 成本增加。部署 HTTPS 后,因为 HTTPS 协议的工作要增加额外的计算资源消耗,例如 SSL 协议加密算法和 SSL 交互次数将占用一定的计算资源和服务器成本。在大规模用户访问应用的场景下,服务器需要频繁地做加密和解密操作,几乎每一个字节都需要做加解密,这就产生了服务器成本。随着云计算技术的发展,数据中心部署的服务器使用成本在规模增加后逐步下降,相对于用户访问的安全提升,其投入成本已经下降到可接受程度。
SPDY
**SPDY **:2009年,谷歌研发,主要解决 HTTP/1.1 效率不高的问题,综合HTTPS和HTTP两者有点于一体的传输协议
- 通过压缩标头、对请求进行优先级排序和多路复用,它将把所有 TCP 请求和连接变成单独的一个!具体来说,当你读取 HTML 时,浏览器会查看你在页面中要询问的所有内容。然后,它可以一次获取所有内容,这样就可以避免一个文件一个文件地获取了。
- 基于HTTPS的加密协议传输
- 允许服务器未经请求,主动向客户端发送资源,服务端推送(server push)
如上图所示, SPDY 位于 HTTP 之下,TCP 和 SSL 之上,这样可以轻松兼容老版本的 HTTP 协议 (将 HTTP1.x 的内容封装成一种新的 frame 格式),同时可以使用已有的 SSL 功能。
SPDY 协议在 Chrome 浏览器上证明可行以后,就被当作 HTTP/2 的基础,主要特性都在 HTTP/2 中得到继承。HTTP2 的第一份草案基于 SPDY。今天,互联网上 42.7%的内容使用 HTTP2。
http/2.0
http/2.0:2015年,HTTP/2 基于 SPDY,HTTP/2 完全兼容 HTTP/1,是“更安全的 HTTP、更快的 HTTPS",最大的目标是在用户和网站间只用一个连接(connec-tion)
HTTPS工作方式:
需要TCP握手建立TLS连接,只是TLS连接完成后,发送一个HTTP2的连接确认消息,确认后,客户端服务器使用HTTP2进行连接通讯。
HTTP/2 由两个规范(Specification)组成:
-
Hypertext Transfer Protocol version 2 - RFC7540
-
HPACK - Header Compression for HTTP/2 - RFC7541
- 二进制传输
HTTP/2 传输数据量的大幅减少, 主要有两个原因: 以二进制方式传输和 Header 压缩。我们先来介绍二进制传输,HTTP/2 采用二进制格式传输数据,而非 HTTP/1.x 里纯文本形式的报文 ,二进制协议解析起来更高效。HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
它把 TCP 协议的部分特性挪到了应用层,把原来的"Header+Body"的消息"打散"为数个小片的二进制"帧"(Frame), 用"HEADERS"帧存放头数据、"DATA"帧存放实体数据。HTTP/2 数据分帧后,“Header+Body"的报文结构就完全消失了,协议看到的只是一个个"碎片”。头信息和数据体都是二进制,称为头信息帧和数据帧。
HTTP/2 中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。
- Header 压缩
HTTP/2 并没有使用传统的压缩算法,而是开发了专门的"HPACK”算法,在客户端和服务器两端同时维护一张头信息表,所有字段都会存入这个表。用索引号表示重复的字符串,不发送同样字段,只发送索引号。还采用哈夫曼编码来压缩整数和字符串,可以达到 50%~90% 的高压缩率。
具体来说:
- 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键 - 值对,对于相同的数据,不再通过每次请求和响应发送。
- 首部表在 HTTP/2 的连接存续期内始终存在,由客户端和服务器共同渐进地更新 。
- 每个新的首部键 - 值对要么被追加到当前表的末尾,要么替换表中之前的值。
例如下图中的两个请求, 请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销 。
- 多路复用
在 HTTP/2 中引入了多路复用的技术。复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,且不用按顺序一一对应,避免了“队头堵塞“,此双向的实时通信称为多工(Multiplexing)。
多路复用很好地解决了浏览器限制同一个域名下请求数量的问题,同时也更容易实现全速传输,毕竟新开一个 TCP 连接都需要慢慢提升传输速度。
大家可以通过该链接直观感受下 HTTP/2 比 HTTP/1 到底快了多少: https://http2.akamai.com/demo
在 HTTP/2 中,有了二进制分帧之后,HTTP /2 不再依赖 TCP 链接去实现多流并行了,在 HTTP/2 中:
- 同域名下所有通信都在单个连接上完成。
- 单个连接可以承载任意数量的双向数据流。
- 数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。
这一特性使性能有了极大提升:
- 同个域名只需要占用一个 TCP 连接,使用一个连接并行发送多个请求和响应, 这样整个页面资源的下载过程只需要一次慢启动,同时也避免了多个 TCP 连接竞争带宽所带来的问题。
- 并行交错地发送多个请求 / 响应,请求 / 响应之间互不影响。
- 在 HTTP/2 中,每个请求都可以带一个 31bit 的优先值,0 表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。
如上图所示,多路复用的技术只通过一个 TCP 连接就可以传输所有的请求数据。
- Server Push
HTTP2 还在一定程度上改变了传统的“请求 - 应答”工作模式,服务器不再完全被动地响应请求,也可以新建“流”主动向客户端发送消息。比如,在浏览器刚请求 HTML 的时候就提前把可能会用到的 JS、CSS 文件发给客户端,减少等待的延迟,这被称为"服务器推送"( Server Push,也叫 Cache push)。
如下图所示,服务端主动把 JS 和 CSS 文件推送给客户端,而不需要客户端解析 HTML 时再发送这些请求。
另外需要补充的是,服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送 RST_STREAM 帧来拒收。主动推送也遵守同源策略。换句话说,服务器不能随便将第三方资源推送给客户端,而必须是经过双方确认才行。
- 提高安全性
出于兼容的考虑,HTTP/2 延续了 HTTP/1 的“明文”特点,可以像以前一样使用明文传输数据,不强制使用加密通信,不过格式还是二进制,只是不需要解密。
但由于 HTTPS 已经是大势所趋,而且主流的浏览器 Chrome、Firefox 等都公开宣布只支持加密的 HTTP/2,所以“事实上”的 HTTP/2 是加密的。也就是说,互联网上通常所能见到的 HTTP/2 都是使用"https”协议名,跑在 TLS 上面。HTTP/2 协议定义了两个字符串标识符:“h2"表示加密的 HTTP/2,“h2c”表示明文的 HTTP/2。
HTTP2.0和SPDY区别
- HTTP2.0 支持明文 HTTP 传输,而 SPDY 强制使用 HTTPS
- HTTP2.0 消息头的压缩算法采用 HPACK,而非 SPDY 采用的 DEFLATE
HTTP/2 的缺点
虽然 HTTP/2 解决了很多之前旧版本的问题,但是它还是存在一个巨大的问题,主要是底层支撑的 TCP 协议造成的。HTTP/2 的缺点主要有以下几点:
- TCP 和 TCP+TLS 建立连接的延时
HTTP/2 是使用 TCP 协议来传输的。如果使用 HTTPS 的话,还需要使用 TLS 协议进行安全传输,而使用 TLS 也需要一个握手过程,这样就需要有两个握手延迟过程:
①在建立 TCP 连接的时候,需要和服务器进行三次握手来确认连接成功,也就是说需要在消耗完 1.5 个 RTT 之后才能进行数据传输。
②进行 TLS 连接,TLS 有两个版本——TLS1.2 和 TLS1.3,每个版本建立连接所花的时间不同,大致是需要 1~2 个 RTT。
总之,在传输数据之前,我们需要花掉 3~4 个 RTT。
- TCP 的队头阻塞并没有彻底解决
上文我们提到在 HTTP/2 中,多个请求是跑在一个 TCP 管道中的。但当出现了丢包时,HTTP/2 的表现反倒不如 HTTP/1 了。因为 TCP 为了保证可靠传输,有个特别的“丢包重传”机制,丢失的包必须要等待重新传输确认,HTTP/2 出现丢包时,整个 TCP 都要开始等待重传,那么就会阻塞该 TCP 连接中的所有请求(如下图)。而对于 HTTP/1.1 来说,可以开启多个 TCP 连接,出现这种情况反倒只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。
为什么不直接去修改 TCP 协议?其实这已经是一件不可能完成的任务了。因为 TCP 存在的时间实在太长,已经充斥在各种设备中,并且这个协议是由操作系统实现的,更新起来不大现实。
QUIC
QUIC:快速 UDP Internet 连接
QUIC 基于 UDP,而 UDP 是“无连接”的,根本就不需要“握手”和“挥手”,所以就比 TCP 来得快。此外,QUIC 也实现了可靠传输,保证数据一定能够抵达目的地。它还引入了类似 HTTP/2 的“流”和“多路复用”,单个“流"是有序的,可能会因为丢包而阻塞,但其他“流”不会受到影响。具体来说,QUIC 协议有以下特点:
- 实现了类似 TCP 的流量控制、传输可靠性的功能。
虽然 UDP 不提供可靠性的传输,但 QUIC 在 UDP 的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些 TCP 中存在的特性。
HTTP3由HTTP2进化,HTTP2最大的变化就是基于二进制流的传输。那么到HTTP3,QUIC协议使用流ID取代IP和端口,HTTP3本身就减负了,将流管理下移QUIC,而本身直接调用QUIC的接口就可以了,这样就能实现连接迁移。
TCP协议使用五元组来表示一条唯一的连接,当我们从4G环境切换到wifi环境时,手机的IP地址就会发生变化,这时必须创建新的TCP连接才能继续传输数据。
QUIC协议基于UDP实现摒弃了五元组的概念,使用64位的随机数作为连接的ID,并使用该ID表示连接。
基于QUIC协议之下,我们在日常wifi和4G切换时,或者不同基站之间切换都不会重连,从而提高业务层的体验。
- 实现了快速握手功能。
由于 QUIC 是基于 UDP 的,所以 QUIC 可以实现使用 0-RTT 或者 1-RTT 来建立连接,这意味着 QUIC 可以用最快的速度来发送和接收数据,这样可以大大提升首次打开页面的速度。0RTT 建连可以说是 QUIC 相比 HTTP2 最大的性能优势。
QUIC的0RTT也是需要条件的,对于第一次交互的客户端和服务端0RTT也是做不到的,毕竟双方完全陌生。
DH算法开辟了密钥交换的新思路,在之前的文章中提到的RSA算法也是基于这种思想实现的,但是DH算法和RSA的密钥交换不完全一样。
- 首次连接
客户端和服务端的密钥协商和数据传输过程,其中交换算法是DH(Diffie-Hellman)迪菲-赫尔曼算法:
- 客户端对于首次连接的服务端先发送client hello请求。
- 服务端生成一个素数p和一个整数g,同时生成一个随机数 (笔误-此处应该是Ks_pri)为私钥,然后计算出公钥 = mod p,服务端将,p,g三个元素打包称为config,后续发送给客户端。
- 客户端随机生成一个自己的私钥,再从config中读取g和p,计算客户端公钥 = mod p。
- 客户端使用自己的私钥和服务端发来的config中读取的服务端公钥,生成后续数据加密用的密钥K = mod p。
- 客户端使用密钥K加密业务数据,并追加自己的公钥,都传递给服务端。
- 服务端根据自己的私钥和客户端公钥生成客户端加密用的密钥K = mod p。
- 为了保证数据安全,上述生成的密钥K只会生成使用1次,后续服务端会按照相同的规则生成一套全新的公钥和私钥,并使用这组公私钥生成新的密钥M。
- 服务端将新公钥和新密钥M加密的数据发给客户端,客户端根据新的服务端公钥和自己原来的私钥计算出本次的密钥M,进行解密。
- 之后的客户端和服务端数据交互都使用密钥M来完成,密钥K只使用1次。
- 非首次连接
前面提到客户端和服务端首次连接时服务端传递了config包,里面包含了服务端公钥和两个随机数,客户端会将config存储下来,后续再连接时可以直接使用,从而跳过这个1RTT,实现0RTT的业务数据交互。
客户端保存config是有时间期限的,在config失效之后仍然需要进行首次连接时的密钥交换。
- 集成了 TLS 加密功能。
目前 QUIC 使用的是 TLS1.3,相较于早期版本 TLS1.3 有更多的优点,其中最重要的一点是减少了握手所花费的 RTT 个数。
- 多路复用,彻底解决 TCP 中队头阻塞的问题。
和 TCP 不同,QUIC 实现了在同一物理连接上可以有多个独立的逻辑数据流(如下图)。实现了数据流的单独传输,就解决了 TCP 中队头阻塞的问题。
http/3.0
http/3.0:2018年
HTTP3 是 HTTP2 的复用和压缩,又称为HTTP Over QUIC,其弃用TCP协议,改为使用基于UDP协议的QUIC协议来实现。
-
TCP 必须进行多次往返,才能以方形且稳定的方式建立连接。
-
UDP 不会顾虑那么多,到同一服务器的重复连接的延迟几乎为零,因为不需要往返来建立连接,能大大减少请求中的延迟,代价是稳定性下降和丢包的风险。
-
QUIC 基于 UDP 实现 。又汲取了 TCP 中的精华用来自建层,以确保稳定性、数据包接收顺序及安全性,实现了既快又可靠的协议。
HTTP3 在保持 QUIC 稳定性的同时使用 UDP 来实现高速度,同时又不会牺牲 TLS 的安全性。是的,在 QUIC 中就有 TLS1.3,你可以用它发起优雅的 SSL。这些层的底层机制是下面这样:
HTTP3工作方式:
首先要建立好HTTP2连接,然后发送HTTP2扩展帧,这个帧包含IP和端口,浏览器收到扩展帧,使用该IP和端口,使用QUIC建立连接,如果成功,断开HTTP2,升级为HTTP3。