为啥说 HTTP2 是二进制协议?
Posted
技术标签:
【中文标题】为啥说 HTTP2 是二进制协议?【英文标题】:Why is it said that HTTP2 is a binary protocol?为什么说 HTTP2 是二进制协议? 【发布时间】:2020-02-18 05:46:39 【问题描述】:我刚刚阅读了一篇关于 http1 和 http2 之间区别的文章,但我的主要问题是,当它说 http2 是二进制文件时协议,但http1是文本协议。
也许我错了,但我知道任何数据,文本或任何格式的数据在内存中都有二进制表示形式,即使通过 TCP/IP 网络传输,数据也会根据层拆分为格式(OSI 模型或 TCP/IP 模型表示)这意味着从技术上讲,文本格式不存在于通过网络传输数据的上下文中。
所以我无法真正理解 http2 和 http1 之间的这种区别,您能帮我解释一下吗?
【问题讨论】:
【参考方案1】:二进制可能是一个令人困惑的术语 - 在计算机中的某个时刻,一切最终都是二进制的!
HTTP/2 具有高度结构化的格式,其中 HTTP 消息被格式化为数据包(称为帧),并且每个帧都分配给一个流。 HTTP/2 frames have a specific format,包括在每帧开始时声明的长度以及帧头中的各种其他字段。在许多方面,它就像一个 TCP 数据包。读取 HTTP/2 帧可以遵循一个定义的过程(前 24 位是这个数据包的长度,后面是 8 位定义帧类型......等等)。在帧头之后是有效负载(例如 HTTP 标头或正文有效负载),这些也将采用预先已知的特定格式。一条 HTTP/2 消息可以在一帧或多帧中发送。
相比之下,HTTP/1.1 是一种非结构化格式,由 ASCII 编码的文本行组成 - 所以是的,它最终以二进制形式传输,但它基本上是一个字符流,而不是专门分成单独的片段/帧(其他比线)。 HTTP/1.1 消息(或至少第一个 HTTP 请求/响应行和 HTTP 标头)通过一次读取一个字符来解析,直到到达新的行字符。这有点混乱,因为您事先不知道每行有多长,因此您必须逐个字符地处理它。在 HTTP/1.1 中,HTTP 正文的长度处理稍有不同,因为通常提前知道 content-length
HTTP 标头将定义这一点。一条 HTTP/1.1 消息必须作为一个连续的数据流完整地发送,并且连接不能用于其他任何事情,只能在完成之前传输该消息。
HTTP/2 带来的好处是,通过将消息打包到特定的帧中,我们可以混合消息:这里有一点请求 1,这里有一点请求 2,这里有一些请求 1……等等。在 HTTP/1.1 中这是不可能的,因为 HTTP 消息没有被包装到数据包/帧中,并带有一个 ID 来表明它属于哪个请求。
我有一个图表 here 和一个动画版本 here 可以帮助更好地概念化这一点。
【讨论】:
【参考方案2】:例如:
Connection: keep-alive
在http1.1中
在 http1.1 中会被编码成(通常是 utf-8):
Connection: keep-alive
只是文字。
在http2中
事先客户端和服务器已经就一些值集合达成一致,例如:
headerField: ['user-agent','cookie', 'connection',...]
connection-values: ['keep-alive', 'close'...]
那么Connection: keep-alive
会被编码成:
2:0
结束
这里是一个类似于http2二进制协议的协议:thrift binary protocol
【讨论】:
“按字节分隔”是什么意思?【参考方案3】:我相信 HTTP/2 使用二进制编码的主要原因是将有效负载打包到固定大小的帧中。 纯文本不能完全适合框架。因此,对数据进行二进制编码并将其拆分为多个帧会更有意义。
【讨论】:
【参考方案4】:HTTP 基本上将所有相关指令编码为 ASCII 码点,例如:
GET /foo HTTP/1.1
是的,这在实际传输层上以字节表示,但命令基于 ASCII 字节,因此可以作为文本读取。
HTTP/2 使用实际的二进制命令,即单个位和字节,除了它们的位和字节之外没有其他表示,因此没有可读的表示。 (请注意,HTTP/2 本质上将 HTTP/1 包装在这样的二进制协议中,在其中的某处仍然可以找到“GET /foo
”。)
【讨论】:
有一个方法GET
和一个路径/foo
,是的,但实际上不是GET /foo
...以上是关于为啥说 HTTP2 是二进制协议?的主要内容,如果未能解决你的问题,请参考以下文章