HTTP/1.1 与 HTTP/2.0 | 青训营笔记

433 阅读13分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第4篇笔记

1、HTTP/1.1

1.1、请求与响应
1.1.1、新增方法
  • 新增方法:options / trace / connect
  • 淘汰 link 、 unlink

http_newMethod.png

1.1.2、响应状态码
  • HTTP/1.0仅定义了16种状态码。

  • HTTP/1.1中新加入了大量的状态码,光是错误响应状态码就新增了24种。如:

    • 100 (Continue)——在请求大资源前的预热请求,
    • 206 (Partial Content)——范围请求的标识码,
    • 409 (Conflict)——请求与当前资源的规定冲突,
    • 410 (Gone)——资源已被永久转移,而且没有任何已知的转发地址
1.2、缓存处理
  • 缓存技术通过避免用户与源服务器的频繁交互,节约了大量的网络带宽,降低了用户接收信息的延迟。
1.2.1、HTTP/1.0
  • HTTP/1.0提供的缓存机制非常简单。
  • 服务器端使用Expires标签来标志(时间)一个响应体,在Expires标志时间内的请求,都会获得该响应体缓存。
  • 服务器端在初次返回给客户端的响应体中,有一个Last-Modified标签,该标签标记了被请求资源在服务器端的最后一次修改。
  • 在请求头中,使用If-Modified-Since标签,该标签标志一个时间,意为客户端向服务器进行问询:该时间后资源是否被修改过。通常情况下,请求头中的If-Modified-Since的值即为上一次获得该资源时,响应体中的Last-Modified的值。
  • 如果服务器接收到了请求头,并判断If-Modified-Since时间后,资源确实没有修改过,则返回给客户端一个304 not modified响应头,并示意浏览器可以使用缓存。
  • 如果服务器判断If-Modified-Since时间后,资源被修改过,则返回给客户端一个200 OK的响应体,并附带全新的资源内容。

http1_cache.png

1.2.2、HTTP/1.1
  • HTTP/1.1的缓存机制在HTTP/1.0的基础上,大大增加了灵活性和扩展性。
  • 基本工作原理和HTTP/1.0保持不变,增加了更多细致的特性。其中,请求头中最常见的特性就是Cache-Control首部字段
1.3、连接方式
1.3.1、HTTP/1.0 短链接
  • HTTP/1.0 默认使用短连接 ,也就是说,客户端和服务器每进行一次 HTTP 操作,就建立一次连接,任务结束就中断连接。
  • 当客户端浏览器访问的某个 HTML 或其他类型的 Web 页中包含有其他的 Web 资源,每遇到这样一个 Web 资源,浏览器就会重新建立一个TCP连接,这样就会导致有大量的“握手报文”和“挥手报文”占用了带宽( 每次进行一次 HTTP 通讯就要断开一次 TCP 连接 )。
1.3.2、HTTP/1.1 持久连接(长连接)
  • HTTP/1.1 默认使用持久连接 HTTP keep-alive,只要双方没有明确断开连接,就保持 TCP 连接
  • 采用长连接模式的请求报文会通知服务端保持连接状态,该TCP连接将持续打开,为后续的客户端-服务端的数据交互服务。
  • 即在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输 HTTP 数据的 TCP 连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。
  • 如果 TCP 连接一直保持的话也是对资源的浪费,因此,一些服务器还会支持超时时间的时间。在超时时间之内没有新的请求达到,TCP 连接才会被关闭。

有必要说明的是,HTTP/1.0仍提供了长连接选项,即在请求头中加入Connection: Keep-alive。同样的,在HTTP/1.1中,如果不希望使用长连接选项,也可以在请求头中加入Connection: close

HTTP 协议的长连接和短连接,实质上是 TCP 协议的长连接和短连接。

1.3.3、管线化(pipelining
  • 长连接的一个缺点是请求和响应式是顺序执行的,只有在请求1的响应收到之后,才会发送请求2;而管线化不需要等待上一次请求得到响应就可以进行下一次请求
  • HTTP/1.1 , 在长连接的基础上,将客户端的其他请求都交给这一个连接去处理(HTTP/1.0不支持)
  • 管线化技术出现后, 不用等待响应亦可直接发送下一个请求。

http_管线化.png

1.4、Host 头处理
  • 域名系统(DNS)允许多个主机名绑定到同一个IP地址上,但是HTTP/1.0并没有考虑这个问题
  • 假设我们有一个资源URL是 example1.org/home.html,HTTP/1.0的请求报文中,将会请求的是GET /home.html HTTP/1.0.也就是不会加入主机名。这样的报文送到服务器端,服务器是理解不了客户端想请求的真正网址。
  • 因此,HTTP/1.1在请求头中加入了Host字段。
// 加入Host字段的报文头部
GET /home.html HTTP/1.1
Host:example1.org
1.5、带宽优化
1.5.1、请求范围
  • HTTP/1.1引入了范围请求(range request)机制,以避免带宽的浪费。
  • 当客户端想请求一个文件的一部分,或者需要继续下载一个已经下载了部分但被终止的文件,HTTP/1.1可以在请求中加入Range头部,以请求(并只能请求字节型数据)数据的一部分。服务器端可以忽略Range头部,也可以返回若干Range响应。
  • 如果一个响应包含部分数据的话,那么将带有206 (Partial Content)状态码。该状态码的意义在于避免了HTTP/1.0代理缓存错误地把该响应认为是一个完整的数据响应,从而把他当作为一个请求的响应缓存。
  • 在范围响应中,Content-Range头部标志指示出了该数据块的偏移量和数据块的长度
1.5.2、状态码100
  • 在HTTP/1.0中,并没有100 (Continue)状态码,要想触发这一机制,可以发送一个Expect头部,其中包含一个100-continue的值。
  • HTTP/1.1中新加入了状态码100。该状态码的使用场景为,存在某些较大的文件请求,服务器可能不愿意响应这种请求,此时状态码100可以作为指示请求是否会被正常响应
1.5.3、压缩
  • 许多格式的数据在传输时都会做预压缩处理。数据的压缩可以大幅优化带宽的利用。然而,HTTP/1.0对数据压缩的选项提供的不多,不支持压缩细节的选择,也无法区分端到端(end-to-end)压缩或者是逐跳(hop-by-hop)压缩。
  • HTTP/1.1则对内容编码(content-codings)和传输编码(transfer-codings)做了区分。内容编码总是端到端的,传输编码总是逐跳的。
  • HTTP/1.0包含了Content-Encoding头部,对消息进行端到端编码。
  • HTTP/1.1加入了Transfer-Encoding头部,可以对消息进行逐跳传输编码。HTTP/1.1还加入了Accept-Encoding头部,是客户端用来指示他能处理什么样的内容编码

2、HTTP/2.0

  • http2.0是一种安全高效的http传输协议。安全是因为http2.0建立在https协议的基础上,高效是因为它是通过二进制分帧来进行数据传输。
  • http/2.0协议是在http/1.x基础上的升级而不是重写,http/1.x协议的方法,状态及api在http/2.0协议里是一样的, http/2.0协议重点是对终端用户的感知延迟、网络及服务器资源的使用等性能的优化
2.1、二进制分帧
  • http2.0之所以能够突破http1.X标准的性能限制,改进传输性能,实现低延迟和高吞吐量,就是因为其新增了二进制分帧层
  • 在二进制分帧层上,http2.0会将所有传输信息分割为更小的消息和帧,并对它们采用二进制格式的编码将其封装,新增的二进制分帧层同时也能够保证http的各种动词,方法,首部都不受影响,兼容上一代http标准。其中,http1.X中的首部信息header封装到Headers帧中,而request body将被封装到Data帧中。
  • 帧(frame)组成:类型Type, 长度Length, 标记Flags, 流标识Streamframe payload有效载荷
  • 消息(message) :一个完整的请求或者响应,由一个或多个 Frame 组成
  • 流是连接中的一个虚拟信道,可以承载双向消息传输。每个流有唯一整数标识符。为了防止两端流ID冲突,客户端发起的流具有奇数ID,服务器端发起的流具有偶数ID
  • 流标识是描述二进制frame的格式,使得每个frame能够基于http2发送,与流标识联系的是一个流,每个流是一个逻辑联系,一个独立的双向的frame存在于客户端和服务器端之间的http2连接中。一个http2连接上可包含多个并发打开的流,这个并发流的数量能够由客户端设置。

multilplex.png

2.2、多路复用
  • 在http1.1中,浏览器客户端在同一时间,针对同一域名下的请求有一定数量的限制,超过限制数目的请求会被阻塞( 队头阻塞 )。
  • 而http2.0中的多路复用优化了这一性能。多路复用允许同时通过单一的http/2 连接发起多重的请求-响应消息。有了新的分帧机制后,http/2.0 不再依赖多个TCP连接去实现多流并行。每个数据流都拆分成很多互不依赖的帧,而这些帧可以交错(乱序发送),还可以分优先级,最后再在另一端把它们重新组合起来。
  • http 2.0 连接都是持久化的,而且客户端与服务器之间也只需要一个连接(每个域名一个连接)。http2连接可以承载数十或数百个流的复用,多路复用意味着来自很多流的数据包能够混合在一起通过同样连接传输。当到达终点时,再根据不同帧首部的流标识符重新连接将不同的数据流进行组装。

http2_multipaly.png

2.2.1、http/2.0 多路复用与 http/1.x 管线化的区别

pipelining_multiplex.png

  • 图一,就是单次发送request请求,收到response后再进行下一次请求,显示是很低效的。
  • 于是http1.1提出了管线化(pipelining)技术,图二中,一次性发送多个request请求。
  • 然而pipelining在接收response返回时,也必须依顺序接收,如果前一个请求遇到了阻塞,后面的请求即使已经处理完毕了,仍然需要等待阻塞的请求处理完毕。这种情况就如图三,第一个请求阻塞后,后面的请求都需要等待,这也就是队头阻塞(Head of line blocking)。
  • 为了解决上述阻塞问题,http2中提出了多路复用(Multiplexing)技术。http2中将多个请求复用同一个tcp链接中,将一个TCP连接分为若干个流(Stream),每个流中可以传输若干消息(Message),每个消息由若干最小的二进制帧(Frame)组成。也就是将每个request-response拆分为了细小的二进制帧Frame,这样即使一个请求被阻塞了,也不会影响其他请求,如图中第四种情况所示
2.3、头部压缩
  • http1.x的头带有大量信息,而且每次都要重复发送。http/2.0使用encoder来减少需要传输的header大小,通讯双方各自缓存一份头部字段表,既避免了重复header的传输,又减小了需要传输的大小。
  • 对于相同的数据,不再通过每次请求和响应发送,通信期间几乎不会改变
  • 如果首部发生了变化,则只需将变化的部分加入到header帧中,改变的部分会加入到头部字段表中,首部表在 http 2.0 的连接存续期内始终存在,由客户端和服务器共同渐进地更新。
  • 需要注意的是,http 2.0关注的是首部压缩,而常用的gzip等是报文内容(body)的压缩
2.3.1、压缩算法 HPACK
  • http/2.0使用的是专门为首部压缩而设计的 HPACK 算法
  • 算法使用一份索引表来定义常用的http Header,把常用的 http Header 存放在表里,请求的时候便只需要发送在表里的索引位置即可( 用header字段表里的索引代替实际的header
2.4、请求优先级
  • 把http消息分为很多独立帧之后,就可以通过优化这些帧的交错和传输顺序进一步优化性能。每个流都可以带有一个31比特的优先值:0 表示最高优先级;2的31次方-1 表示最低优先级

  • 服务器可以根据流的优先级,控制资源分配(CPU、内存、带宽),而在响应数据准备好之后,优先将最高优先级的帧发送给客户端。

  • 分配处理资源和客户端与服务器间的带宽,不同优先级的混合也是必须的。客户端会指定哪个流是最重要的,通过依赖参数,这样一个流可以依赖另外一个流。

  • 优先级别可以在运行时动态改变,当用户滚动页面时,可以告诉浏览器哪个图像是最重要的,也可以在一组流中进行优先筛选,能够突然抓住重点流。

  • 优先级顺序例子

    • 优先级最高:主要的html
    • 优先级高:CSS文件
    • 优先级中:js文件
    • 优先级低:图片
2.5、服务器推送
  • 服务器可以对一个客户端请求发送多个响应,服务器向客户端推送资源无需客户端明确地请求。并且,服务端推送能把客户端所需要的资源伴随着index.html一起发送到客户端,省去了客户端重复请求的步骤。

  • 服务器推送还有一个很大的优势:缓存,也让在遵循同源的情况下,不同页面之间可以共享缓存资源成为可能

  • 当服务端需要主动推送某个资源时,便会发送一个 Frame Type 为 PUSH_PROMISE 的 Frame,里面带了 PUSH 需要新建的 Stream ID。意思是告诉客户端:接下来我要用这个 ID 向你发送东西,客户端准备好接着。客户端解析 Frame 时,发现它是一个 PUSH_PROMISE 类型,便会准备接收服务端要推送的流。

  • 注意

    • 服务器推送遵循同源策略
    • 服务端的推送是基于客户端的请求响应来确定

参考连接