通过 HTTP/2 通过 websocket 发送冗余数据实际上是免费的吗?

Is sending redundant data over websocket over HTTP/2 practically free?

我正在编写一个 Web 应用程序功能,该功能将使用 WebSocket 消息在客户端和服务器之间传输 JSON 结构。该应用程序最简单的协议是不断重复来回发送大部分冗余部分。 HTTP/2 压缩能否有效地压缩来回的单独消息中的冗余部分? 我知道这在理论上应该是可行的,但在实践中怎么样?

示例:

假设 shared_state 是一个 大部分 相同但不同消息之间不相同的字符串:

客户端连接:

ws = new WebSocket("wss://myserver.example/foo/bar");

客户端通过 WebSocket 连接发送消息:

{ command: "foo", shared_state: "...long data here..." }

服务器发送:

{ command: "bar", shared_state: "...long data here slightly modified..." }

客户端发送:

{ command: "zoo", shared_state: "...long data here slightly modified again..." }

所有这些消息都将使用单个 websocket 通过单个 HTTP/2 连接传递。

双向发送的消息会被HTTP/2压缩吗?这意味着后面的数据包可以有效地使用一些对先前在同一 HTTP/2 连接中传输的数据中已经看到的数据的引用。如果我可以继续发送共享状态而不是仅仅发送 delta 而不会在实践中导致高带宽使用,这将简化我需要实现的自定义协议。不支持HTTP/2.

的老客户不用管

我假设消息之间的差异小于 1 KB,但包括冗余部分在内的整个消息通常在 10-60 KB 范围内。

WebSocket 在 HTTP/2 上的工作方式是 WebSocket 帧在 HTTP/2 DATA 帧中作为不透明字节进行传输。 逻辑 WebSocket 连接由单个 HTTP/2 流承载,具有“无限”请求内容和“无限”响应内容,因为 DATA 帧(包含 WebSocket 帧)继续从客户端流向服务器并从服务器到客户端。

由于 WebSocket 字节由 DATA 帧承载,因此 HTTP/2 级别没有进行“压缩”。

HTTP/2 仅在 HEADERS 帧中通过 HPACK 为 HTTP headers 提供“压缩”,但 HTTP/2 上的 WebSocket 无法利用它(因为它不使用 HTTP/2 HEADERS 帧).

您的自定义协议有 key/value 对,但它是由 DATA 帧承载的 WebSocket 负载。

您将获得的唯一“压缩”是由 WebSocket 的 permessage-deflate 功能驱动的。

例如,浏览器会打开一个连接,在 HTTP/2 上建立 WebSocket(使用 WebSocket 升级期间协商的 permessage-deflate 扩展名),然后发送 WebSocket 消息。 WebSocket 消息将被压缩,压缩后的字节打包成 WebSocket 帧,WebSocket 帧打包成 HTTP/2 DATA 帧,然后通过网络发送。

如果您的 shared_state 压缩得很好,那么您就是在用网络带宽(较少的网络字节数)换取 CPU 使用(解压缩)。 如果它压缩不好,那么它可能不值得。

我建议您查看基于 WebSocket 的现有协议,可能已经有一些协议可以满足您的需求(例如,Bayeux)。

此外,请考虑不使用 JSON 作为格式,因为现在 JavaScript 支持二进制,因此您可能会更有效率(参见示例 CBOR)。