前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HTTP2基础教程-读书笔记(四)

HTTP2基础教程-读书笔记(四)

作者头像
前端黑板报
发布2018-03-21 16:58:41
1K0
发布2018-03-21 16:58:41
举报
文章被收录于专栏:前端黑板报前端黑板报

记录一下HTTP/2的底层原理,帮助理解协议实现细节。

连接

每个端点都需要发送一个连接作为最终确认使用的协议,并建立http/2连接的初始设置。客户端和服务器各自发送不同的连接前导(preface)。

客户端的连接前导以24位的序列开头,下面是16进制表示:

代码语言:javascript
复制
0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a

也就是下面字符串:

这个序列后面必须跟着 SETTINGS 帧,其有可能为空。

服务端的连接前导由一个可能为空的 SETTINGS 帧组成,它在 HTTP/2 的连接中必须是第一个帧。

一旦连接前导交换过之后,连接就认为已经建立。端点可利用它进行通讯。

建立连接之后,就可以交换帧。所有帧的格式如下:

前面9个字节是固定的,代表整个帧的大小。

下面解释一下各个字段的含义:

名称

长度

描述

Length

3字节

帧负载的长度

Type

1字节

当前帧类型

Flags

1字节

具体帧类型的标识

R

1位

保留位,不要设置

Stream Identifier

31位

每个流的唯一ID

Frame Payload

长度可变

真实的帧内容

h2中有10种不同类型的帧,如下表:

名称

ID

描述

DATA

0x0

传输流的核心内容

HEADERS

0x1

包含HTTP首部和可选的优先级参数

PRIORITY

0x2

指示或更改流的优先级和依赖

RST_STREAM

0x3

允许一端停止流(通常由于错误导致)

SETTINGS

0x4

协商连接级参数

PUSH_PROMISE

0x5

提示客户端,服务器要推送些东西

PING

0x6

测试连接可用性和往来时延(RTT)

GOWAY

0x7

告诉另一端,当前端已结束

WINDOW_UPDATE

0x8

协商一端将要接受多少字节(用户流量控制)

CONTINUATION

0x9

用以扩展HEADER数据块

“流”是在http/2连接中客户端和服务端之间交换的一个独立的、双向的帧序列。流包含很多重要的特性:

  • 一个http/2连接可以包含多个并发的开放流和多个流中交错的帧
  • 流可由客户端或服务端单方面建立、使用或分享
  • 流可由其中任何一个端点关闭
  • 流中帧的顺序很重要,接收者以它们被接收的顺序处理。特别是,HEADERS 和 DATA 帧从语义上来说非常重要
  • 流是由一个整数标识,流ID 是在端点初始化流时被分配的

消息

HTTP消息泛指HTTP请求或响应。流是用来传输一对请求/响应消息的。一个消息至少由 HEADERS 帧组成,并且可以另外包含 CONTINUATION 和 DATA帧,以及其他的 HEADERS 帧。

下面是普通GET请求:

下面展示POST请求:

流量控制

不同h1,h2提供客户端调整传输速度的能力,服务器也可以控制。 WINDOW_UPDATE 帧用来指示流量控制信息。客户端需要流量控制的理由:

  • 确保某个流不会阻塞其他流
  • 可用带宽和内存比较有限

目前为止流量控制没有提供开发控制。

优先级

h2使用流的依赖关系来解决服务器同时收到很多请求不知道如何处理的问题。客户端明确地和服务端沟通需要的资源以及它们的顺序。通过声明依赖关系树和树里的相对权重:

  • 依赖关系:为客户端提供了一种能力,通过指明某些对象对另一些对象有依赖,告知服务器这些对象应该优先传输
  • 权重让客户端告诉服务器如何确定具有共同依赖关系的对象的优先级

服务端推送

提升单个对象性能的最佳方式,就是在它被用到之前就放到浏览器的缓存里。服务端推送同时伴随着一些安全问题。

推送对象

若服务器决定推送一个对象,会构造一个PUSH_PROMISE帧:

  • PUSH_PROMISE帧首部中的流ID用来关联相关联的请求
  • PUSH_PROMISE帧的首部块与客户端请求推送对象时发送的首部块是相似的。
  • 被发送的对象必须确保是可缓存的
  • :metch首部的值必须确保安全
  • 理想情况下,PUSH_PROMISE帧应早于客户端接受到可能承载着推送对象的DATA帧
  • PUSH_PROMISE 帧会有对应流的ID

客户端设置的流从1开始,使用奇数,而服务端开启的流使用偶数,从2开始。这种设计避免了客户端和服务器之间流ID冲突,也可以轻松判断哪些对象是由服务端推送的。0是保留数字,用于连接级控制消息,不能用于创建新的流。

客户端使用RST_STREAM或PROTOCOL_ERROR(专门留给PUSH_PROMISE涉及的协议层面问题)来拒收。值得注意的是,服务器可以在PUSH_PROMISE发送后立即启动推送流,因此拒收推送仍然无法避免推送大量资源,所以推送正确的资源时不够的,还需要只推送正确的资源

PUSH_PROMISE 中指明所属流的ID:

首部压缩

现在网页平均包含140个请求,这些请求之间通常几乎没有新的或不同的内容,造成很大浪费,急需压缩方法。经过思考和讨论提出了HPACK,它是一种表查找压缩方案,利用霍夫曼编码获得接近GZIP的压缩率,同时能抵御CRIME。

如上两个请求,只有红框中的不同其余都是重复的。HPACK是为减少传输相同部分而设计出来的。简化原理如下:

假设客户端发送如下请求首部:

代码语言:javascript
复制
Header1:foo
Header2:bar
Header3:bat

同时客户端会创建一张表:

索引

首部名称

62

Header1

foo

63

Header2

bar

64

Header3

bat

服务端读取到请求首部,照样会创建一张表。客户端发送下一个请求时,若首部相同,可直接发送如下首部块:

代码语言:javascript
复制
62 63 64

服务器会查找先前的表格,把数字还原成索引对应的完整首部。

HPCK实现比上面的复杂得多,提供如下线索更深理解:

  • 请求端和响应端各维护两张表格,一个动态表,另一个是61个常见首部的键值组合而成。
  • 如何索引字段:1.发送索引编号和文本值;2.仅发送文本值,不对他们进行索引;3.发送索引的首部名,值用文本表示,但不进行索引处理;4.发送索引过的首部名和值
  • 使用打包方案的证书压缩,以实现极高的空间效率
  • 利用霍夫曼编码表进一步压缩字符串
  1. HTTP2基础教程-读书笔记(一)
  2. HTTP2基础教程-读书笔记(二)
  3. HTTP2基础教程-读书笔记(三)
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-02-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端黑板报 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档