Http2协议简介
1.概述
- 和http1兼容。HTTP/2 没有改动 HTTP 的应用语义。 HTTP 方法、状态代码、URI 和标头字段等核心概念一如往常。 不过,HTTP/2 修改了数据格式化(分帧)以及在客户端与服务器间传输的方式。因此,所有现有的应用都可以不必修改而在新协议下运行。
- 传输方式改变。在HTTP/1.x中,每个 TCP 连接同时只能处理一个请求 - 响应,一个请求就会独占一个链接,用户想要多个并行的请求来提高性能,必须得使用多个TCP连接(对于同一个域名Chrome最多只能同时创建 6 个 TCP 连接)。这也是被人吐槽的原因,也是http2 要解决的一个痛点,解决方法是在链接的基础上提出了stream的概念,通过stream 来区别不同的请求 。
2.连接多路复用
在一个 TCP 连接上,我们可以向对方不断发送帧,每帧的 stream identifier 的标明这一帧属于哪个流,然后在对方接收时,根据 stream identifier 拼接每个流的所有帧组成一整块数据。
把 HTTP/1.1 每个请求都当作一个流,那么多个请求变成多个流,请求响应数据分成多个帧,不同流中的帧交错地发送给对方,这就是 HTTP/2 中的多路复用。
流的概念实现了单连接上多请求 - 响应并行,解决了线头阻塞的问题。
(1) 帧
+---+-----------+------------+-------------+-------------+
|Bit| ... | ... | ... | ... |
+---+-----------+------------+-------------+-------------+
| | Length | Type |
+---+-----------+--------------------------+-------------+
| |Flags |
+---+-+---------+----------------------------------------+
| |R| Stream Identifier |
+---+-+--------------------------------------------------+
|...| Frame Payload |
+---+----------------------------------------------------+
字段含义:
- Length 代表整个 frame 的长度,用一个 24 位无符号整数表示。
- Type 定义 frame 的类型,用 8 bits 表示。帧类型决定了帧主体的格式和语义,如果 type 为 unknown 应该忽略或抛弃。
- Flags 是为帧类型相关而预留的布尔标识。标识对于不同的帧类型赋予了不同的语义。如果该标识对于某种帧类型没有定义语义,则它必须被忽略且发送的时候应该赋值为 (0x0) 。
- R 是一个保留的比特位。这个比特的语义没有定义,发送时它必须被设置为 (0x0), 接收时需要忽略。
- Stream Identifier 用作流控制,用 31 位无符号整数表示。客户端建立的 sid 必须为奇数,服务端建立的 sid 必须为偶数,值 (0x0) 保留给与整个连接相关联的帧 (连接控制消息),而不是单个流 。
- Frame Payload 是主体内容,由帧类型决定。
共分为十种类型的帧:
- HEADERS: 报头帧 (type=0x1),用来打开一个流或者携带一个首部块片段
- DATA: 数据帧 (type=0x0),装填主体信息,可以用一个或多个 DATA 帧来返回一个请求的响应主体
- PRIORITY: 优先级帧 (type=0x2),指定发送者建议的流优先级,可以在任何流状态下发送 PRIORITY 帧,包括空闲 (idle) 和关闭 (closed) 的流
- RST_STREAM: 流终止帧 (type=0x3),用来请求取消一个流,或者表示发生了一个错误,payload 带有一个 32 位无符号整数的错误码 (Error Codes),不能在处于空闲 (idle) 状态的流上发送 RST_STREAM 帧
- SETTINGS: 设置帧 (type=0x4),设置此 连接 的参数,作用于整个连接
- PUSH_PROMISE: 推送帧 (type=0x5),服务端推送,客户端可以返回一个 RST_STREAM 帧来选择拒绝推送的流
- PING: PING 帧 (type=0x6),判断一个空闲的连接是否仍然可用,也可以测量最小往返时间 (RTT)
- GOAWAY: GOWAY 帧 (type=0x7),用于发起关闭连接的请求,或者警示严重错误。GOAWAY 会停止接收新流,并且关闭连接前会处理完先前建立的流
- WINDOW_UPDATE: 窗口更新帧 (type=0x8),用于执行流量控制功能,可以作用在单独某个流上 (指定具体 Stream Identifier) 也可以作用整个连接 (Stream Identifier 为 0x0),只有 DATA 帧受流量控制影响。初始化流量窗口后,发送多少负载,流量窗口就减少多少,如果流量窗口不足就无法发送,WINDOW_UPDATE 帧可以增加流量窗口大小
- CONTINUATION: 延续帧 (type=0x9),用于继续传送首部块片段序列,见 首部的压缩与解压缩
(2) 消息
一个HTTP2请求或响应被分为N个帧传送,在另一端再重新组合为完整的消息。
(3) 流
流是一个逻辑上的概念,代表 HTTP/2 连接中在客户端和服务器之间交换的独立双向帧序列,每个帧的 Stream Identifier 字段指明了它属于哪个流。 流有以下特性:
- 单个连接可以包含多个流,两端之间可以交叉发送不同流的帧
- 流可以由客户端或服务器来单方面地建立和使用,或者共享
- 流可以由任一方关闭
- 帧在流上发送的顺序很重要,最后接收方会把相同 Stream Identifier (同一个流) 的帧重新组装成完整的消息

3.HTTP头压缩
简单说,HTTP头压缩需要在HTTP/2 客户端和服务端之间:
- 维护一份相同的静态表(Static Table),包含常见的头部名称,以及特别常见的头部名称与值的组合;
- 维护一份相同的动态表(Dynamic Table),可以动态地添加内容;
- 基于静态哈夫曼码表的哈夫曼编码(Huffman Coding);
(1) 静态索引
静态索引表是固定的,对于客户端服务端都一样,目前协议商定的静态索引包含 61 个键值,详见 Static Table Definition - RFC 7541
前几个如下
| 索引 | 字段值 | 键值 |
|---|---|---|
| 1 | :authority | |
| 2 | :method | GET |
| 3 | :method | POST |
| 4 | :path | / |
| 5 | :path | /index.html |
| 6 | :scheme | http |
| 7 | :scheme | https |
| 8 | :status | 200 |
(2) 动态索引
动态索引表是一个 FIFO 队列维护的有空间限制的表,里面含有非静态表的索引。
动态索引表是需要连接双方维护的,其内容基于连接上下文,一个 HTTP2 连接有且仅有一份动态表。
当一个首部匹配不到索引时,可以选择把它插入动态索引表中,下次同名的值就可能会在表中查到索引并替换。
但是并非所有首部键值都会存入动态索引,因为动态索引表是有空间限制的,最大值由 SETTING 帧中的 SETTINGS_HEADER_TABLE_SIZE (默认 4096 字节) 设置
4.HTTP/2 的协议协商机制
客户端在不知道服务器是否支持HTTP2协议时需要使用HTTP Upgrade 机制。
客户端首先发起一个 HTTP/1.1 请求,其中包含Upgrade首部字段,还必须包含一个且只能一个 HTTP2-Settings 首部字段。
例如:
GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/ SETTINGS payload>
- Upgrade。"h2c" 标示运行在明文 TCP 之上的 HTTP/2 协议。"h2" 标示使用了 TLS(Transport Layer Security)[TLS12] 的 HTTP/2 协议
- HTTP2-Settings。是一个连接相关的首部字段,它提供了用于管理 HTTP/2 连接的参数(前提是服务端接受了升级请求)
不支持 HTTP/2 的服务端响应请求时,可以认为 Upgrade 首部字段不存在。
支持 HTTP/2 的服务器响应状态码 101 (Switching Protocols) 表示接受升级协议的请求。在结束 101 响应之后,服务端可以开始发送 HTTP/2 帧。
例如:
HTTP/1.1 Switching Protocols
Connection: Upgrade
Upgrade: h2c [ HTTP/ connection ...
客户端一收到 101(Switching Protocols) 响应(表示成功升级)后,就发送客户端连接前奏。客户端连接前奏以一个固定的24字节的序列开始,用十六进制表示为:0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a(相当于一个魔法值,在WireSark可以看到标识为Magic)。
为了避免不必要的延迟,允许客户端发送完连接前奏后就立即向服务端发送其他的帧,而不必等待服务端的连接前奏。
服务端发送的第一个 HTTP/2 帧必须是由一个 SETTINGS 帧组成的服务端连接前奏。
两端都要发送一个连接前奏,作为对所使用协议的最终确认,并确定 HTTP/2 连接的初始设置。
5.流量控制
多路复用的流会竞争 TCP 资源,进而导致流被阻塞。流控制机制确保同一连接上的流不会相互干扰。流量控制作用于单个流或整个连接。HTTP/2 通过使用 WINDOW_UPDATE 帧来提供流量控制。 流控制具有以下特征:
- 流量控制是特定于连接的。两种级别的流量控制都位于单跳的端点之间,而不是整个端到端的路径。比如 server 前面有一个 front-end proxy 如 Nginx,这时就会有两个 connection,browser-Nginx, Nginx—server,flow control 分别作用于两个 connection。详情见: How is HTTP/2 hop-by-hop flow control accomplished? - stackoverflow
- 流量控制是基于 WINDOW_UPDATE 帧的。接收方公布自己打算在每个流以及整个连接上分别接收多少字节。这是一个以信用为基础的方案。
- 流量控制是有方向的,由接收者全面控制。接收方可以为每个流和整个连接设置任意的窗口大小。发送方必须尊重接收方设置的流量控制限制。客户方、服务端和中间代理作为接收方时都独立地公布各自的流量控制窗口,作为发送方时都遵守对端的流量控制设置。
- 无论是新流还是整个连接,流量控制窗口的初始值是 65535 字节。
- 帧的类型决定了流量控制是否适用于帧。目前,只有 DATA 帧会受流量控制影响,所有其它类型的帧并不消耗流量控制窗口的空间。这保证了重要的控制帧不会被流量控制阻塞。
- 流量控制不能被禁用。
- HTTP/2 只定义了 WINDOW_UPDATE 帧的格式和语义,并没有规定接收方如何决定何时发送帧、发送什么样的值,也没有规定发送方如何选择发送包。具体实现可以选择任何满足需求的算法。
(1) WINDOW_UPDATE 帧格式
+-+-------------------------------------------------------------+
|R| Window Size Increment () |
+-+-------------------------------------------------------------+
- Window Size Increment 表示除了现有的流量控制窗口之外,发送端还可以传送的字节数。取值范围是 1 到 2^31 - 1 字节。
WINDOW_UPDATE 帧可以是针对一个流或者是针对整个连接的。如果是前者,WINDOW_UPDATE 帧的流标识符指明了受影响的流;如果是后者,流标识符为 0 表示作用于整个连接。
流量控制功能只适用于被标识的、受流量控制影响的帧。文档定义的帧类型中,只有 DATA 帧受流量控制影响。除非接收端不能再分配资源去处理这些帧,否则不受流量控制影响的帧必须被接收并处理。如果接收端不能再接收帧了,可以响应一个 FLOW_CONTROL_ERROR 类型的流错误或者连接错误。
(2) 流量控制窗口
流量控制窗口是一个简单的整数值,指出了准许发送端传送的数据的字节数。窗口值衡量了接收端的缓存能力。
新建连接时,流和连接的初始窗口大小都是 2^16 - 1(65535) 字节。可以通过设置连接前言中 SETTINGS 帧的 SETTINGS_INITIAL_WINDOW_SIZE 参数改变流的初始窗口大小,这会作用于所有流。而连接的初始窗口大小不能改,但可以用 WINDOW_UPDATE 帧来改变流量控制窗口,这是为什么连接前言往往带有一个WINDOW_UPDATE 帧的原因。
Http2协议简介的更多相关文章
- 【HTTP】一、HTTP协议简介及其工作流程
协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器. (一 ...
- 轻松让你的nginx服务器支持HTTP2协议
目录 简介 HTTP1.1和HTTP2 安装最新的nginx 开启HTTP2支持 添加SSL支持 修改加密算法 Diffie–Hellman对消息进行加密 重定向所有的HTTP请求到HTTPS 启动n ...
- Fiddler--一、HTTP协议简介
在学习Fiddler之前,最好先学习一下HTTP协议. HTTP协议简介 什么是HTTP协议 超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端 ...
- MODBUS-RTU通讯协议简介
MODBUS-RTU通讯协议简介 什么是MODBUS? MODBUS 是MODICON公司最先倡导的一种软的通讯规约,经过大多数公司 的实际应用,逐渐被认可,成为一种标准的通讯规约,只要按照这种规 ...
- JavaWeb:Web与HTTP协议简介
JavaWeb:Web与HTTP协议简介 Web的概念 什么是Web: Web是网络上使用最广泛的分布式应用架构. 旨在共享分布在网络上的各个Web服务器中的所有互相连接的信息. 三个特征: 用HTM ...
- CC2540开发板学习笔记(九)—— BLE协议简介
一.BLE协议简介 1.协议是什么? 协议是一系列的通信标准,双方需要共同按照这进行正常数据 协议是一系列的通信标准,双方需要共同按照这进行正常数据发射和 接收.协议栈是的具体实现形式,通俗点来理解就 ...
- HTTP 协议简介
HTTP 协议简介 博客分类: acl开发--HTTP协议篇 网络协议http协议 一.TCP/IP 协议介绍 在介绍 HTTP 协议之前,先简单说一下TCP/IP协议的相关内容.TCP/IP协议是 ...
- HTTP2协议之HPACK--之头部压缩规范介绍
接下来打算把HTTP2协议的头部压缩算法给翻译下,敬请等候. HPACK - Header Compression for HTTP/2 HPACK:HTTP/2头部压缩 概要说明 这个规范定义了HP ...
- OAUTH协议简介
OAUTH协议简介 原文来自:http://blog.csdn.net/hereweare2009/article/details/3968582 分类: Open API2009-03-08 12: ...
随机推荐
- jenkins连接gitlab,提示returned status code 128,附解决办法
在项目中配置git仓库地址,报无权限 Failed to connect to repository : Command "D:\Program Files\Git\mingw64\bin\ ...
- html5中的选择器
1.html5中的属性选择器 <body> <style type=text/css> <!--1>完全匹配选择器--> [id=test]{ color:r ...
- java--字符串拼接比较
/** * 字符串拼接 */ public class StringAddDemo { public static void main(String[] args){ testStringAdd(); ...
- 杂谈、 素材资源,没有美工不会ps一样可以美观
免费素材网站 阿里巴巴矢量图,大部分图标都有颜色像素可选,格式可选3种, http://www.iconfont.cn/plus/home/index?spm=a313x.7781069.199891 ...
- securityDemo依赖
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit ...
- 【Flutter学习】事件处理与通知之事件处理
一,概述 移动应用中一个必不可少的环节就是与用户的交互,在Flutter中提供的手势检测为GestureDetector. Flutter中的手势系统分为二层: 第一层是触摸原事件(指针) Point ...
- 浏览器 url 编码
1.问题的由来 : http://www.ruanyifeng.com/blog/2010/02/url_encoding.html 2.网络标准RFC 1738做了硬性规定: 只有字母和数字[0-9 ...
- LG1017 进制转换:负数进制
题目描述 我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减1)为指数,以10为底数的幂之和的形式.例如:123可表示为 1×102+2×101+3×1001\ ...
- 【已转移】【Java架构:基础技术】一篇文章搞掂:Spring
本文篇幅较长,建议合理利用右上角目录进行查看(如果没有目录请刷新). 本文是对<SPRING实战第4版>的总结,大家也可以去仔细研读该书 [------------------------ ...
- Linux系统Centos查看IP地址,不显示IP地址或者显示127.0.0.1
1.桌面界面 右上角有个电脑的图标,鼠标悬停会显示no network connect 点击一下图标,选择连接的网络则ok 2.命令行界面 在命令行界面输入 vi /etc/sysconfig/ne ...