比较 http、http2、https

HTTP/0.9

HTTP 的最早版本诞生在 1991 年,它没有 HTTP 头,没有状态码,甚至版本号也没有,是后来才被定为 0.9 来和其他版本区分。

只支持一种方法------ Get,请求只有一行:GET /hello.html

响应也只包含 html 文档本身:<HTML> Hello world </HTML>

服务器向客户端返回 HTML 格式的字符串。发送完毕后,就关闭 TCP 连接。由于没有状态码和错误代码,如果服务器处理的时候发生错误,只会传回一个特殊的包含问题描述信息的 HTML 文件。这就是最早的 HTTP/0.9 版本。

HTTP/1.0

1996 年,HTTP/1.0 版本发布,大大丰富了 HTTP 的传输内容,除了文字,还可以发送图片、视频等。

主要有如下特性:

  • 请求与响应支持 HTTP 头,增加了状态码,响应对象的一开始是一个响应状态行
  • 协议版本信息需要随着请求一起发送,支持 HEAD,POST 方法
  • 支持传输 HTML 文件以外其他类型的内容

HTTP/1.1

在 HTTP/1.0 发布几个月后,HTTP/1.1 就发布了。HTTP/1.1 更多的是作为对 HTTP/1.0 的完善。

但 HTTP/1.0 在 1999 年才开始广泛应用于现在的各大浏览器网络请求中,同时也是当前使用最为广泛的 HTTP 协议。

主要区别主要体现在:

1.长连接

HTTP1.0 默认是短连接,每次与服务器交互,都需要新开一个连接。

在 HTTP1.1 中默认持久连接:只要没有明确提出端口就一直保持,可以发送多次 HTTP 请求:Connection: keep-alive

2.分块/断点传输

引入了 transfer-coding: chunked(分块传输)的消息头,实现断点续传:实际上就是使用分块传输编码,将实体主体分块传输。

请求头 range,它表示了要请求资源的哪个部分。如果服务器相应地返回了所请求的范围的内容,在响应头 Content-Range 中声明返回的这部分对象的偏移值和长度,响应码为 206(Partial Content),可以防止 Cache 将响应误以为是完整的。

加入了一个新的状态码 100(Continue)。客户端事先发送一个只带头域的请求,如果服务器因为权限拒绝了请求,就回送响应码 401(Unauthorized);如果服务器接收此请求就回送响应码 100,客户端就可以继续发送带实体的完整请求了。注意,HTTP/1.0 的客户端不支持 100 响应码。但可以让客户端在请求消息中加入 Expect 头域,并将它的值设置为 100-continue。

3.Host 头域

请求消息和响应消息都支持,表示访问资源所在的主机名,即 URL 中的域名部分。如:m.baidu.com

在 HTTP1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此,请求消息中的 URL 并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个 IP 地址。因此,Host 头的引入就很有必要了。

4.缓存处理

在 HTTP1.0 中是使用下面头域来做为缓存判断的标准

  • 强缓存:Expires(请求头、响应头中都有)
  • 协商缓存:if-modified-since(请求头)、last-modified(响应头)

HTTP1.1 则引入了更多可供选择的缓存头来控制缓存策略。

  • 强缓存:cache-control
  • 协商缓存:if-none-match(请求头)、Etag(响应头)

5.增加 pipeline

HTTP 管线化,在持久连接前提下,将多个 HTTP 请求整批提交的技术,而在传送过程中不需先等待服务端的回应。可大幅缩短页面的加载时间。有一点需要注意的是,只有幂等的请求可以使用 pipeline,如 GET,HEAD 方法。

在 HTTP1.0 中,发送一次请求时,需要等待服务端响应了才可以继续发送请求。

在 HTTP1.1 中,发送一次请求时,不需要等待服务端响应了就可以发送请求了,但是回送数据给客户端的时候,客户端还是需要按照响应的顺序来一一接收。所以,无论是 HTTP1.0 还是 HTTP1.1 提出的 Pipelining 理论,还是会出现阻塞的情况。从专业的名词上说,叫做队头阻塞(Head of line blocking)。

但是 pipeline 仅仅是限于理论的阶段上,这个功能默认还是关闭了的。

缺点

无状态

在需要长连接的场景中,需要保存大量的上下文信息,以免传输大量重复的信息,这时无状态就是 http 的缺点。

但与此同时,另外一些应用仅仅只是为了获取一些数据,不需要保存连接上下文信息,无状态反而减少了网络开销,成为了 http 的优点。

解决办法

为了记录状态,引入了 Cookie 技术

明文传输

即协议里的报文(主要指的是头部)不使用二进制数据,而是文本形式。

这当然对于调试提供了便利,但同时也让 HTTP 的报文信息暴露给了外界,给攻击者也提供了便利。WIFI陷阱 就是利用 HTTP 明文传输的缺点,诱导你连上热点,然后疯狂抓你所有的流量,从而拿到你的敏感信息。

解决办法

HTTP + TSL = HTTPS

队头阻塞

当 http 开启长连接时,共用一个 TCP 连接,当某个请求时间过长时,其他的请求只能处于阻塞状态,这就是队头阻塞问题。通常我们提到队头阻塞,指的可能是 TCP 协议中的队头阻塞,但是 HTTP1.1 中也有一个类似 TCP 队头阻塞的问题。

  1. TCP 的队头阻塞:TCP 要求数据严格按照序号顺序,前一个报文没有收到便不会将后面收到的报文上传给 HTTP
  2. HTTP 的队头阻塞:HTTP 管道化要求服务端必须按照请求发送的顺序返回响应,那如果一个响应返回延迟了,那么其后续的响应都会被延迟,直到队头的响应送达。

两者所在的层次不一样。TCP 的队头阻塞是在数据包层面,单位是数据包,而 HTTP 的队头阻塞是在 HTTP 请求-响应层面。

解决办法

1.并发连接

一个域名允许分配多个长连接,那么相当于增加了任务队列,不至于一个队伍的任务阻塞其它所有任务(Chrome 中是 6 个)

2.域名分片

一个域名可以并发 6 个长连接,那就多分几个域名。

在一个域名下分出多个二级域名出来,而它们最终指向的还是同一个服务器,这样子的话就可以并发处理的任务队列更多。

比如 woc12138.com,可以分出很多二级域名,比如 Day1.woc12138.comDay2.woc12138.comDay3.woc12138.com

3.HTTP2 的多路复用

上面两种方法并没有真正从 HTTP 本身的层面解决问题,只是增加了 TCP 连接,分摊风险而已。而且这么做也有弊端,多条 TCP 连接会竞争有限的带宽,让真正优先级高的请求不能优先处理。

而 HTTP/2 便从 HTTP 协议本身解决了队头阻塞问题。注意,这里并不是指的TCP队头阻塞,而是HTTP队头阻塞

HTTP2 不使用管道化的方式,而是引入了帧、消息和数据流等概念,每个请求/响应被称为消息,每个消息都被拆分成若干个帧进行传输,每个帧都分配一个序号。每个帧在传输是属于一个数据流,而一个连接上可以存在多个流,各个帧在流和连接上独立传输,到达之后在组装成消息,这样就避免了请求/响应阻塞。

HTTP 2

2015 年 HTTP/2.0 问世。

对于 HTTP/1.x,即使开启了长连接,请求的发送也是串行发送的,在带宽足够的情况下,对带宽的利用率不够,HTTP/2.0 与 HTTP1.1 最重要的区别就是解决了队头阻塞的问题。

其中最重要的改动是:

1.二进制分帧层

HTTP1.x 的解析是基于文本,解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景很多;二进制则不同,只认 0 和 1 的组合。HTTP2.0 的协议解析采用二进制分帧格式,实现方便且健壮。

在应用层(HTTP)与传输层(TCP + TLS)之间增加一个二进制分帧层(Binary Framing),HTTP2.0 会将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码,其中 HTTP1.x 的首部信息会被用 frame 封装到 Headers 帧,而 request body 则用 frame 封装到 Data 帧里面。

2.多路复用 (Multiplexing)

分帧之后,服务器看到的不再是一个个的 HTTP 请求报文,而是一堆乱序的二进制帧,这些帧不分前后关系,也就不会排队等待,就没有了 HTTP 的队头阻塞问题。

通信双方都可以给对方发送二进制帧,这种二进制帧的双向传输的序列,也叫做(Stream)。HTTP/2 用来在一个 TCP 连接上来进行多个数据帧的通信,这就是多路复用的概念。

这里的乱序指的是不同 ID 的 Stream 是乱序的,但同一个 Stream ID 的帧一定是按顺序传输的。二进制帧到达后对方会将 Stream ID 相同的二进制帧组装成完整的请求报文响应报文

3.header 压缩

HTTP1.x 的 header 带有大量信息,每次请求 header 基本不怎么变化,每次都要重复发送。HTTP2.0 使用 HPACK 算法来压缩需要传输的 header 大小,通讯时在服务器和客户端之间建立哈希表,将用到的字段存放在这张表中,那么在传输的时候对于之前出现过的值,只需要把索引(0,1,2,...)传给对方,对方拿到索引查表即可。

4.服务端推送

在 HTTP/2.0 中,服务器可以向客户发送请求之外的内容,比如正在请求一个页面时,服务器会把页面相关的 logo,CSS 等文件直接推送到客户端,而不会等到请求来的时候再发送,因为服务器认为客户端会用到这些东西。当客户端再次尝试获取这些资源时就可以直接从缓存中获取到,不用再发请求了。

5.数据流优先级

由于请求可以并发发送了,如果出现了浏览器在等待关键的 CSS 或者 JS 文件完成对页面的渲染时,服务器却在专注的发送图片资源的情况时,HTTP/2.0 对数据流可以设置优先值,这个优先值决定了客户端和服务端处理不同的流采用不同的优先级策略。

HTTPS

HTTP 是 HTTP 的安全版,实际就是在 TCP 层与 HTTP 层之间加入了 SSL/TLS 来为安全保驾护航,主要用到对称加密、非对称加密、证书,等技术进行客户端与服务器的数据加密传输。HTTPS = HTTP + TLS/SSL

  • SSL 是安全套接层(secure sockets layer):在 OSI 七层模型中处于会话层(第 5 层),1.0、2.0 已废除、3.0 基本废除。
  • TLS 是 SSL 的继任者,叫传输层安全(transport layer security):TLS1.0 = SSL3.1,现在主流的版本是 TLS/1.2,之前的 TLS1.0、TLS1.1 都被认为是不安全的,在不久的将来会被完全淘汰。

工作原理

1.对称加密

加密和解密都是用的同一个密钥

传输信息的双方都要知道对称密钥,通过密钥加密传输的信息,但是一端生成一个对称密钥,然后通过 HTTP 传输给另一端又是不安全的,可能被中间人拦截获取到这个密钥。使用对称加密的方式,行不通,所以我们需要采用非对称加密。

2.非对称加密

公钥加密的内容,只有私钥可以解开,私钥加密的内容,所有的公钥都可以解开。公钥可以发送给所有客户端,私钥只保存在服务器端,两者成对出现。

想要安全的传递信息,A 可以用公钥加密信息传递给 B,B 用私钥解密看到信息的内容。只要 B 的私钥不泄露,信息就算被其他人获取到也无法解密。

但是,又出现了一个问题:虽然别人不知道私钥是什么,拿不到你原始传输的数据,但是可以拿到加密后的数据,他们可以改掉某部分的数据再发送给服务器,这样服务器拿到的数据就不是完整的了。于是,就出现了数字签名来解决被篡改的问题。

3.数字签名

  • 验证传输的内容是对方发送的数据(认证)
  • 验证发送的数据有没有被篡改过(保证完整性)

也可以看做是非对称加密的手段一种,就是把公钥私钥的用法反过来,之前是公钥加密、私钥解密,现在是私钥加密、公钥解密。

  1. B 先用摘要算法(常用的有 SHA224、SHA256、SHA384),生成信息的摘要(digest)
MD5 也是摘要算法,但是不够安全,在 TSL 里已经被禁止使用了。

  1. 然后使用私钥,对这个摘要加密,生成"数字签名"(signature)
如果不对摘要加密,那么摘要也有可能被篡改。

  1. 将这个签名,和信息一起发给 A
  2. A 收到后用公钥解密数字签名,得到摘要,由此证明,信息确实是 B 发出的。
  3. 再对信息本身使用 Hash 函数,将得到的结果,与上一步得到的摘要进行对比。如果两者一致,就证明信息未被修改过。

但是,复杂的情况又出现了:如果 C 将 A 原本有的 B 的公钥换成自己伪造的公钥。这时,A 以为自己拥有的是 B 的公钥,但实际上是 C 的。所以,C 就可以冒充 B,发送信息给 A,然后 A 用伪造的公钥解密比对后并没有出现问题。

于是,就出现了CA 认证机构来确认公钥的真实性。

4.数字证书认证机构(Certificate Authority)

简称 CA,认证机构将证明是真实的服务器发送的数据。

每一个使用 HTTPS 的服务器都必须去专门的证书机构注册一个证书,证书中存储了用权威机构私钥加密的公钥。这样客户端用权威机构的公钥解密就可以了。

步骤

1.A(Client)发起一个 HTTPS 请求,连接 443 端口。这个过程可以理解成是请求公钥的过程

2.B(Server)端收到请求后,用 CA自己的私有密钥B公钥 + B各种信息加密生成数字签名,然后把数字证书(也可以认为是公钥证书,由B公钥+B各种信息加密后生成的数字签名 组成)发送给 A。(这样子的话,数字证书包含有两个特别重要的信息

评论已关闭
暂无评论