你了解HTTP2协议吗?(一)

1.写在前面

前面的博客我们介绍完了HTTP1.0/1.1的协议,以及WebSocket协议,但是这些协议由于历史的问题,或多或少都有些历史的问题,所以后面的博客我们介绍HTTP2协议,HTTTP2协议的出现,就是为了解决以前这些协议问题。

2.HTTP/1.1发展中遇到的问题

HTTP/1.1发明以来发生了哪些变化?

  • 从几 KB 大小的消息,到几 MB 大小的消息

  • 每个页面小于 10 个资源,到每页面 100 多个资源

  • 从文本为主的内容,到富媒体(如图片、声音、视频)为主的内容

  • 对页面内容实时性高要求的应用越来越多

    在这里插入图片描述

HTTP/1.1的高延迟问题

  • 高延迟带来页面加载速度降低

    • 随着带宽的增加,延迟并没有显著下降

    • 并发连接有限

    • 同一连接同时只能在完成一个 HTTP 事务(请求/响应)才能处理下一个事务

      在这里插入图片描述

高延迟 VS 高带宽

  • 单连接上的串行请求
  • 无状态导致的高传输量(低网络效率)

在这里插入图片描述

无状态特性带来的巨大 HTTP 头部

  • 重复传输的体积巨大的 HTTP 头部

    在这里插入图片描述

HTTP/1.1 为了解决性能问题做过的努力

  • Spriting 合并多张小图为一张大图供浏览器 JS 切割使用
    • 不能区别对待
  • Inlining 内联,将图片嵌入到 CSS 或者 HTML 文件中,减少网络请求次数
  • Concatenation 拼接,将多个体积较小的 JavaScript 使用 webpack 等工具打包成 1个体积更大的 JavaScript 文件
    • 1 个文件的改动导致用户重新下载多个文件
  • Sharding 分片,将同一页面的资源分散到不同域名下,提升连接上限

HTTP/1.1不支持服务器推送消息

在这里插入图片描述

3.HTTP/2 有哪些特性?

解决 HTTP/1 性能问题的 HTTP/2

  • SPDY(2012-2016)

    在这里插入图片描述

  • HTTP2(RFC7540,2015.5)

    • 在应用层上修改,基于并充分挖掘 TCP 协议性能
    • 客户端向 server 发送 request 这种基本模型不会变
    • 老的 scheme 不会变,没有 http2://
    • 使用 http/1.x 的客户端和服务器可以无缝的通过代理方式转接到 http/2 上
    • 不识别 http/2 的代理服务器可以将请求降级到 http/1.x

主流浏览器对 HTTP/2 的支持程度

在这里插入图片描述

HTTP/2 的应用状况

  • 截止 2019.5.17 号,互联网上使用 HTTP/2 协议的站点已经达到 37.2%
  • 快速推广的原因
    • 未改变 HTTP/1.1 的语义
    • 基于 TCP,仅在应用层变动

多路复用带来的提升

在这里插入图片描述

在这里插入图片描述

HTTP/2 的强大之处

  • 我们看如下的网站https://http2.akamai.com/demo进行对比

    在这里插入图片描述

HTTP/2 主要特性

  • 传输数据量的大幅减少
    • 以二进制方式传输
    • 标头压缩
  • 多路复用及相关功能
    • 消息优先级
  • 服务器消息推送
    • 并行推送

4.如何使用 Wireshark 解密 TLS/SSL 报文?

在 HTTP/2 应用层协议之下的 TLS 层

在这里插入图片描述

TLS1.2 的加密算法

  • 常见加密套件

    在这里插入图片描述

  • 对称加密算法:AES_128_GCM

    • 每次建立连接后,加密密钥都不一样
  • 密钥生成算法:ECDHE

    • 客户端与服务器通过交换部分信息,各自独立生成最终一致的密钥

Wireshark 如何解密 TLS 消息?

  • 原理:获得 TLS 握手阶段生成的密钥
    • 通过 Chrome 浏览器 DEBUG 日志中的握手信息生成密钥
  • 步骤
    • 配置 Chrome 输出 DEBUG 日志
      • 配置环境变量 SSLKEYLOGFILE
    • 在 Wireshark 中配置解析 DEBUG 日志
      • 编辑->首选项->Protocols->TLS/SSL
      • (Pre)-Master-Secret log filename

二进制格式与可见性

  • TLS/SSL 降低了可见性门槛
    • 代理服务器没有私钥不能看到内容

在这里插入图片描述

5.h2c:如何从 http:/1.1升级到 HTTP/2 协议?

HTTP/2 是不是必须基于 TLS/SSL 协议?

  • IETF 标准不要求必须基于TLS/SSL协议
  • 浏览器要求必须基于TLS/SSL协议
  • 在 TLS 层 ALPN (Application Layer Protocol Negotiation)扩展做协商,只认HTTP/1.x 的代理服务器不会干扰 HTTP/2
  • shema:http://和 https:// 默认基于 80 和 443 端口
  • h2:基于 TLS 协议运行的 HTTP/2 被称为 h2
  • h2c:直接在 TCP 协议之上运行的 HTTP/2 被称为 h2c

h2 与 h2c

在这里插入图片描述

H2C:不使用 TLS 协议进行协议升级(1)

客户端测试工具:curl(7.46.0版本)

  • curl http://www.nghttp2.org –-http2 -v

    在这里插入图片描述

H2C:客户端发送的 Magic 帧

  • Preface(ASCII 编码,12字节)
    • 何时发送?
      • 接收到服务器发送来的 101 Switching Protocols
      • TLS 握手成功后
    • Preface 内容
      • 0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
      • PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n
    • 发送完毕后,应紧跟 SETTING 帧

统一的连接过程

在这里插入图片描述

6.h2:如何从 https://升级到 HTTP/2 协议?

在 HTTP/2 应用层协议之下的 TLS 层

在这里插入图片描述

TLS 通讯过程

在这里插入图片描述

在这里插入图片描述

Next Protocol Negotiation (NPN)

  • SPDY 使用的由客户端选择协议的 NPN 扩展

    在这里插入图片描述

Application-Layer Protocol Negotiation Extension

在这里插入图片描述

7.Stream、Message、Frame 间的关系

HTTP/2 核心概念

  • 连接 Connection:1个 TCP 连接,包含一个或者多个 Stream

  • 数据流 Stream:一个双向通讯数据流,包含1 条或者多条 Message

  • 消息 Message:对应 HTTP/1 中的请求或者响应,包含一条或者多条 Frame

  • 数据帧 Frame:最小单位,以二进制压缩格式存放 HTTP/1 中的内容

    在这里插入图片描述

Stream、Message、Frame 间的关系

在这里插入图片描述

消息的组成:HEADERS 帧与 DATA 帧

在这里插入图片描述

传输中无序,接收时组装

在这里插入图片描述

消息与帧

在这里插入图片描述

8.帧格式:Stream 流 ID 的作用

对比Websocket的帧格式

在这里插入图片描述

9字节的标准头部

在这里插入图片描述

标准帧头示意

在这里插入图片描述

Stream ID 的作用

实现多路复用的关键

  • 接收端的实现可据此并发组装消息

  • 同一 Stream 内的 frame 必须是有序的(无法并发)

  • SETTINGS_MAX_CONCURRENT_STREAMS 控制着并发 Stream 数

    在这里插入图片描述

推送依赖性请求的关键

  • 由客户端建立的流必须是奇数

  • 由服务器建立的流必须是偶数

    在这里插入图片描述

流状态管理的约束性规定

  • 新建立的流 ID 必须大于曾经建立过的状态为 opened 或者 reserved 的流 ID
  • 在新建立的流上发送帧时,意味着将更小 ID 且为 idle 状态的流置为 closed 状态
  • Stream ID 不能复用,长连接耗尽 ID 应创建新连接

应用层流控仅影响数据帧

  • Stream ID 为 0 的流仅用于传输控制帧

在HTTP/1 升级到 h2c 中,以 ID 为 1 流返回响应,之后流进入half-closed(local)状态

9.帧格式:帧类型及设置帧的子类型

9 字节标准帧头部:帧长度

在这里插入图片描述

  • 0 至 2^14 (16,384) -1
    • 所有实现必须可以支持 16KB 以下的帧
  • 2^14 (16,384) 至 2^24-1 (16,777,215)
    • 传递 16KB 到 16MB 的帧时,必须接收端首先公布自己可以处理此大小
      • 通过 SETTINGS_MAX_FRAME_SIZE 帧(Identifier=5)告知

帧类型 Type

在这里插入图片描述

帧类型

帧类型类型编码用途
DATA0x0传递HTTP包体
HEADERS0x1传递HTTP头部
PRIORITY0x2指定Stream流的优先级
RST_STREAM0x3终止Stream流
SETTINGS0x4修改连接或者Stream流的配置
PUSH_PROMISE0x5服务端推送资源时描述请求的帧
PING0x6心跳检测, 兼具计算RTT往返时间的功能
GOAWAY0x7优雅的终止连接或者通知错误
WINDOW_UPDATE0x8实现流量控制
CONTINUATION0x9传递较大HTTP头部时的持续帧

Setting 设置帧格式(type=0x4)

  • 设置帧并不是“协商”,而是发送方向接收方通知其特性、能力

  • 一个设置帧可同时设置多个对象

    在这里插入图片描述

  • Identifier:设置对象

  • Value:设置值

Setting 设置对象的类型

在这里插入图片描述

设置类型

  • SETTINGS_HEADER_TABLE_SIZE (0x1): 通知对端索引表的最大尺寸(单位字节,初始 4096 字节)
  • SETTINGS_ENABLE_PUSH (0x2): Value设置为 0 时可禁用服务器推送功能,1 表示启用推送功能
  • SETTINGS_MAX_CONCURRENT_STREAMS (0x3): 告诉接收端允许的最大并发流数量
  • SETTINGS_INITIAL_WINDOW_SIZE (0x4): 声明发送端的窗口大小,用于Stream级别流控,初始值2^16-1 (65,535)字节
  • SETTINGS_MAX_FRAME_SIZE (0x5):设置帧的最大大小,初始值 2^14 (16,384)字节
  • SETTINGS_MAX_HEADER_LIST_SIZE (0x6): 知会对端头部索引表的最大尺寸,单位字节,基于未压缩前的头部

10.HPACK 如何减少 HTTP 头部的大小?

HPACK 头部压缩

  • RFC7541
  • 三种压缩方式
    • 静态字典
    • 动态字典
    • 压缩算法:Huffman 编码(最高压缩比 8:5)

静态字典

  • https://httpwg.org/specs/rfc7541.html#static.table.definition

  • 含有 value 的表项

  • 不含有 value 的表项

    在这里插入图片描述

HPACK 压缩示意

  • 同一个索引空间的 HEADER 表

    在这里插入图片描述

索引表用法示意

在这里插入图片描述

HPACK 压缩比:h2load

在这里插入图片描述

11.HPACK 中如何使用 Huffman 树编码?

Huffman 编码

  • 原理:出现概率较大的符号采用较短的编码,概率较小的符号采用较长的编码
  • 静态 Huffman 编码 https://httpwg.org/specs/rfc7541.html#huffman.code
  • 动态 Huffman 编码

Huffman 树的构造过程

  1. 计算各字母的出现概率
  2. 将出现频率最小的两个字母相加构成子树,左小右大
  3. 重复步骤 2,直至完成树的构造
  4. 给树的左链接编码为 0,右链接编码为 1
  5. 每个字母的编码即从根结点至所在叶结点中所有链接的编码

Huffman 树构造过程

  • 有 FORGET 这六个字母需要编码,其出现频率如下

    在这里插入图片描述

    1. 将概率为 2 的 F 与概率为 3 的 O 构成子树,其父结点概率为 5

    2. 将概率为 4 的 R 与概率为 4 的 G 构成子树,其父结点概率为 8

    3. 将概率为 5 的 E 与第 1 步生成的概率为 5 的子树合并

    4. 将概率为 7 的 T 与第 2 步生成的概率为 8 的子树合并

    5. 将第 3 步生成的概率为 10 的子树与第 4 步生成的概率为15 的子树合并

    6. 最终编码如下

      在这里插入图片描述

      在这里插入图片描述

Huffman 编码举例

在这里插入图片描述

12.HPACK 中整型数字的编码

使用 5 位前缀:对小于 31 的整型数字的编码

  • 当数字小于 31(2^5-1)时的编码

    在这里插入图片描述

  • 例如:对 10 进行编码

    在这里插入图片描述

使用 N 位前缀:整型的编码过程

在这里插入图片描述

使用 5 位前缀:对整型大数 1337 的编码举例

在这里插入图片描述

整型的解码过程

在这里插入图片描述

13.HPACK 中 HEADER 的编码格式

HEADER 帧的格式

在这里插入图片描述

CONTINUATION 持续帧(type=0x9)

  • 跟在 HEADER 帧或者 PUSH_PROMISE 帧之后,补充完整的 HTTP 头部

    在这里插入图片描述

同一地址空间下的静态表与动态表

  • 静态表:61 项

  • 动态表:先入先出的淘汰策略

    • 动态表大小由 SETTINGS_HEADER_TABLE_SIZE 设置帧定义

    • 允许重复项

    • 初始为空

      在这里插入图片描述

字面编码

  • 组成
    • header name 和 value 以索引方式编码
    • header name 以索引方式编码,而 header value 以字面形式编码
    • header name 和 value 都以字面形式编码
  • 可控制是否进入动态表
    • 进入动态表,供后续传输优化使用
    • 不进入动态表
    • 不进入动态表,并约定该头部永远不进入动态表

HEADER 二进制编码格式

  • 名称与值都在索引表中(包括静态表与动态表)

    • 编码方式:首位传 1,其余 7 位传索引号

      在这里插入图片描述

    • 例如

      • method: GET在静态索引表中序号为 2,其表示应为 1000 0010,HEX 表示为 82
  • 名称在索引表中,值需要编码传递,同时新增至动态表中

    • 前 2 位传 01

    • 名称举例

      • if-none-match 在静态索引表中序号为 41,表示为 01101001,HEX 表示为 69
    • 值举例

      在这里插入图片描述

  • 名称、值都需要编码传递,同时新增至动态表中

    • 前 2 位传 01

      在这里插入图片描述

  • 名称在索引表中,值需要编码传递,且不更新至动态表中

    • 前 4 位传 0000

      在这里插入图片描述

  • 名称、值都需要编码传递,且不更新至动态表中

    • 前 4 位传 0000

      在这里插入图片描述

  • 名称在索引表中,值需要编码传递,且永远不更新至动态表中

    • 前 4 位传 0001

      在这里插入图片描述

  • 名称、值都需要编码传递,且永远不更新至动态表中

    • 前 4 位传 0001

      在这里插入图片描述

动态表大小的两种控制方式

  • 在 HEADER 帧中直接修改

    在这里插入图片描述

  • 在 SETTING 帧中修改

    • SETTINGS_MAX_HEADER_LIST_SIZE (0x6)

14.写在最后

本节博客,我们主要介绍了下HTTP2的协议的一些功能,接下来的博客我们会继续介绍剩下的HTTP2的协议。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值