http学习分享

早在 HTTP 建立之初,主要就是为了将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。

http目前有

http1.0:最早在网页中使用是在1996年

http1.1:在1999年才开始广泛应用于现在的各大浏览器

http2:2015年正式发布

http3:2018年提出将http-over-quic更名为http3,2019年9月,HTTP/3支持已添加到CloudflareGoogle Chrome(Canary build)。Firefox Nightly在2019年秋季之后添加支持。截至2021年6月,HTTP/3仍然是草案状态

http1.0

HTTP 1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求。

当浏览器发起多个请求时,性能问题就比较明显,每个请求都需要重新建立连接

HTTP1.0最早在网页中使用是在1996年,那个时候只是使用一些较为简单的网页上和网络请求上,而HTTP1.1则在1999年才开始广泛应用于现在的各大浏览器网络请求中,同时HTTP1.1也是当前使用最为广泛的HTTP协议。

http1.1

Http1.1针对http1.0的优化

  1. 缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tagIf-None-Matchcache-control 等更多可供选择的缓存头来控制缓存策略。(可打开此链接,查看request header和response header和下面介绍的对应上:请求头和相应头体验

    1. If-Modified-Since:If-Modified-Since是标准的HTTP请求头标签,在发送HTTP请求时,把浏览器端缓存的资源最后修改时间一起发到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行比较。时间一致:http状态码是304,取浏览器缓存的文件直接展示;时间不一致,http状态码200,浏览器重新缓存新文件;
    2. Expires:资源过期的日期,过期时间未到,直接取浏览器缓存,不发http请求,时间过了就直接读服务器的;
    3. Entity tag:也叫Etag,是服务端生成的,在相应头里,第二次请求的时候,请求头里会有 If-None-Match ,它的值就是Etag的值,如果和服务端的 Etag的值一致,就返回304,否则返回200和文件;(Etag和If-Modified-Since 的 区别?有时开发人员会在修复某些内容后将所有文件上传到服务器,即使内容仅在子集上更改,也会重置所有文件的Last-Modified日期。为了适应这种情况,大多数服务器也会发送一个ETag。 ETag代表实体标记,并且是唯一的标识符,其仅根据文件的内容而改变。大多数服务器实际上使用像SHA256这样的散列函数来计算ETag。
    4. cache-control:它允许服务器控制客户端缓存收到的响应的方式和时长,值包括:max-age(可被缓存多长时间,单位为秒)、public(可被任何缓存区缓存)、private(个人用户可缓存,代理服务器不能缓存)、no-cache(不会指示浏览器是否缓存内容,而是告诉浏览器使用别的方式验证,如etag等)
  2. 带宽优化及网络链接的使用:http1.0中,某个请求发出后,只能返回整个文件,但是HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content)
  3. Host头处理,一个IP地址可以对应多个域名: 一台虚拟主机(服务器)只有一个ip,上面可以放成千上万个网站。当对这些网站的请求到来时,服务器根据Host这一行中的值来确定本次请求的是哪个具体的网站
  4. 长链接:请求头里加上:Connection: keep-alive,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟(为什么?因为上一个链接,请求完成后,链接并没有关闭,而是复用给下一个请求
  5. 错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
  6. chunk:当客户端向服务器请求一个静态页面或者一张图片时,服务器可以很清楚的知道内容大小,然后通过Content-Length消息首部字段告诉客户端需要接收多少数据。但是如果是动态页面等时,服务器是不可能预先知道内容大小,这时就可以使用Transfer-Encoding:chunk模式来传输数据了。即如果要一边产生数据,一边发给客户端,服务器就需要使用"Transfer-Encoding: chunked"这样的方式来代替Content-Length。

http1.1的缺陷

  1. 队头阻塞:队头阻塞是指当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一并被阻塞,会导致客户端迟迟收不到数据。(为什么?因为一个浏览器最大并发连接数是有上限的,当前面的请求一直没有响应的话,链接一直被占着,后面的请求就发不出去。
  2. 无状态特性 :无状态是指协议对于连接状态没有记忆能力。纯净的 HTTP 是没有 cookie 等机制的,每一个连接都是一个新的连接。上一次请求验证了用户名密码,而下一次请求服务器并不知道它与上一条请求有何关联,换句话说就是掉登录态。(为什么是无状态?因为单纯的http请求,每次请求完成后,链接都关闭了,各个链接之间没有关联
  3. 不安全性:传输内容没有加密,中途可能被篡改和劫持。

https

img

握手流程

  1. 首先客户端通过URL访问服务器建立SSL连接。
  2. 服务端收到客户端请求后,会将网站支持的证书信息(证书中包含公钥)传送一份给客户端
  3. 浏览器客户端根据双方同意的安全等级,随机生成会话密钥,然后利用服务端的公钥将会话密钥加密,并传送给服务端。(非对称加密)
  4. 服务器利用自己的私钥解密出会话密钥。(对称加密)
  5. 服务器利用会话密钥加密与客户端之间的通信。(对称加密)

(对称加密和非对称加密要拓展内容比较大,需要单独做个分享)

http2

http2和http1.1的区别:

  1. 多路复用(MultiPlexing)

    首先要区分请求和连接,连接是客户端和服务端建立一个连接,连接成功后才可以发送请求

    多路复用即连接共享,在http1.x,一个链接只能发送一个请求,我们对同一个服务器的请求,如果同时发送多个请求,因为浏览器的最大连接数是有上限的,所以对同一个服务器的请求是需要排队的,但是http2,对同一域名,只有一个链接,多个请求都在同一个连接内发起,没有请求数量的限制。多路复用很好的解决了浏览器限制同一个域名下的请求数量的问题,同时也接更容易实现全速传输,毕竟新开一个 TCP 连接都需要慢慢提升传输速度。

    http2体验

    img

    如上图所示,多路复用的技术可以只通过一个 TCP 连接就可以传输所有的请求数据。

  1. 新的二进制格式(Binary Format):

tcp协议本身只考虑了链接,并没有考虑传输的数据格式,也没有定义只能传输什么数据

http协议是基于tcp协议的,http协议定义了协议只能传输文本

HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多

二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。

接下来我们介绍几个重要的概念:

  • 流:流是连接中的一个虚拟信道,可以承载双向的消息;每个流都有一个唯一的整数标识符(1、2…N);
  • 消息:是指逻辑上的 HTTP 消息,比如请求、响应等,由一或多个帧组成。
  • 帧:HTTP 2.0 通信的最小单位,每个帧包含帧首部,至少也会标识出当前帧所属的流,承载着特定类型的数据,如 HTTP 首部、负荷,等等

HTTP/2 中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。

<img src="https://image.fundebug.com/2019-03-06-2.png" alt="img" style="zoom:67%;" />

  1. header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
  • HTTP/2 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送;
  • 首部表在 HTTP/2 的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
  • 每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值

例如下图中的两个请求, 请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销

img

  1. 服务端推送(server push)

Server Push 即服务端能通过 push 的方式将客户端需要的内容预先推送过去,也叫“cache push”。

可以想象以下情况,某些资源客户端是一定会请求的,这时就可以采取服务端 push 的技术,提前给客户端推送必要的资源,这样就可以相对减少一点延迟时间。当然在浏览器兼容的情况下你也可以使用 prefetch。
例如服务端可以主动把 JS 和 CSS 文件推送给客户端,而不需要客户端解析 HTML 时再发送这些请求。

img

服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送 RST_STREAM 帧来拒收。主动推送也遵守同源策略,换句话说,服务器不能随便将第三方资源推送给客户端,而必须是经过双方确认才行。

http3小拓展

虽然 HTTP/2 解决了很多之前旧版本的问题,但是它还是存在一个巨大的问题,主要是底层支撑的 TCP 协议造成的。

背景:上文提到 HTTP/2 使用了多路复用,一般来说同一域名下只需要使用一个 TCP 连接。但当这个连接中出现了丢包的情况,整个 TCP 都要开始等待重传,也就导致了后面的所有数据都被阻塞了为什么?),但是对于 HTTP/1.1 来说,可以开启多个 TCP 连接,出现这种情况反到只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据,那就会导致 HTTP/2 的表现情况反倒不如 HTTP/1 了。

那么可能就会有人考虑到去修改 TCP 协议,其实这已经是一件不可能完成的任务了。因为 TCP 存在的时间实在太长,已经充斥在各种设备中,并且这个协议是由操作系统实现的,更新起来不大现实。

基于这个原因,Google 就更起炉灶搞了一个基于 UDP 协议的 QUIC 协议,并且使用在了 HTTP/3 上,HTTP/3 之前名为 HTTP-over-QUIC,从这个名字中我们也可以发现,HTTP/3 最大的改造就是使用了 QUIC。

虽然 HTTP/2 支持了多路复用,但是 TCP 协议终究是没有这个功能的。QUIC 原生就实现了这个功能,并且传输的单个数据流可以保证有序交付且不会影响其他的数据流,这样的技术就解决了之前 TCP 存在的问题。

同 HTTP2.0 一样,同一条 QUIC 连接上可以创建多个 stream,来发送多个 HTTP 请求,但是,QUIC 是基于 UDP 的,一个连接上的多个 stream 之间没有依赖。比如 stream2 丢了一个 UDP 包,不会影响后面跟着 Stream3 和 Stream4,不存在 TCP 队头阻塞。虽然 stream2 的那个包需要重新传,但是 stream3、stream4 的包无需等待,就可以发给用户。


上帝遗忘之子
60 声望5 粉丝

全栈,运维