HTTP/2 会让 websockets 过时吗?

Does HTTP/2 make websockets obsolete?

我正在学习 HTTP/2 协议。它是一个带有小消息帧的二进制协议。它允许通过单个 TCP 连接进行流多路复用。从概念上讲,它似乎与 WebSockets 非常相似。

是否有计划淘汰 websockets 并用某种无头 HTTP/2 请求和服务器启动的推送消息替换它们?或者 WebSockets 会补充 HTTP/2?

据我了解HTTP/2不是websocket的替代品,而是旨在标准化SPDY协议。

在HTTP/2中,在后台使用服务器推送来改善客户端从浏览器加载资源。作为开发人员,您在开发过程中并不真正关心它。但是,对于 Websocket,开发人员可以使用 API,它能够使用唯一的全双工连接来消费和推送消息。

这不是一回事,应该是相辅相成的。

我说不(Websockets 并没有过时)。

第一个也是最常被忽视的问题是 HTTP/2 推送不可强制执行,可能会被代理、路由器、其他中介甚至浏览器忽略

即(来自 HTTP2 草案):

An intermediary can receive pushes from the server and choose not to forward them on to the client. In other words, how to make use of the pushed information is up to that intermediary. Equally, the intermediary might choose to make additional pushes to the client, without any action taken by the server.

因此,HTTP/2 推送无法取代 WebSockets。

此外,HTTP/2 连接会在一段时间后关闭。

标准确实如此:

HTTP/2 connections are persistent. For best performance, it is expected that clients will not close connections until it is determined that no further communication with a server is necessary (for example, when a user navigates away from a particular web page) or until the server closes the connection.

但是...

Servers are encouraged to maintain open connections for as long as possible but are permitted to terminate idle connections if necessary. When either endpoint chooses to close the transport-layer TCP connection, the terminating endpoint SHOULD first send a GOAWAY (Section 6.8) frame so that both endpoints can reliably determine whether previously sent frames have been processed and gracefully complete or terminate any necessary remaining tasks.

即使相同的连接允许在打开时推送内容,即使 HTTP/2 解决了 HTTP/1.1 的 'keep-alive' 引入的一些性能问题... HTTP/2 连接不会无限期地保持打开状态。

一旦关闭,网页也不能重新启动 HTTP/2 连接(除非我们回到长拉,也就是说)。

编辑(2017 年,两年后)

HTTP/2 的实现显示多个浏览器 tabs/windows 共享一个 HTTP/2 连接,这意味着 push 永远不知道哪个选项卡/ window 它属于,消除使用 push 作为 Websockets 的替代品。

编辑 (2020)

我不确定为什么人们开始反对这个答案。如果有的话,自最初发布答案以来的这些年证明了 HTTP/2 不能取代 WebSockets 并且并非旨在这样做。

当然,HTTP/2 可能用于 隧道 WebSocket 连接,但这些隧道连接仍需要 WebSocket 协议,它们将影响 [=54] =] 容器行为。

答案是否定的。两者的目标非常不同。甚至还有一个针对 WebSocket over HTTP/2 的 RFC,它允许您通过单个 HTTP/2 TCP 管道建立多个 WebSocket 连接。

WS over HTTP/2 将通过减少打开新连接的时间并允许更多的通信通道而不增加套接字、软 IRQ 和缓冲区的额外费用来节省资源。

https://datatracker.ietf.org/doc/html/draft-hirano-httpbis-websocket-over-http2-01

消息交换和简单流(不是音频、视频流)可以通过Http/2 多路复用和 WebSockets 完成。所以有一些重叠,但 WebSockets 有完善的协议,很多 frameworks/APIs 和更少的 headers 开销。 Here is nice article about the topic.

刚读完 RFC 7540 后,HTTP/2 对所有用例都使用过时的 websockets,除了将 二进制数据 从服务器推送到 JS 网络客户端。 HTTP/2 完全支持二进制 bidi 流(继续阅读),但是浏览器 JS 没有用于使用二进制数据帧的 API 并且 AFAIK 没有计划这样的 API。

对于 bidi 流的所有其他应用程序,HTTP/2 与 websockets 一样好或更好,因为 (1) 规范为您做更多的工作,并且 (2) 在许多情况下它允许更少的 TCP 连接待开原点。

PUSH_PROMISE(俗称服务器推送)不是这里的问题。那只是性能优化。

Websockets 在浏览器中的主要用例是启用双向数据流。所以,我认为 OP 的问题变成了 HTTP/2 是否在浏览器中启用双向流方面做得更好,我认为是的,确实如此。

首先,双向。刚刚阅读 streams section:

的介绍

A "stream" is an independent, bidirectional sequence of frames exchanged between the client and server within an HTTP/2 connection. Streams have several important characteristics:

A single HTTP/2 connection can contain multiple concurrently open streams, with either endpoint interleaving frames from multiple streams.

Streams can be established and used unilaterally or shared by either the client or server.

Streams can be closed by either endpoint.

this 这样的文章(链接在另一个答案中)在 HTTP/2 的这方面是错误的。他们说这不是比迪烟。你看,有一点是HTTP/2做不到的:连接打开后,服务端不能发起普通流,只能发起推流。但是一旦客户端通过发送请求打开一个流,双方就可以随时通过持久套接字发送数据帧——完全双向。

这与 websockets 没有太大区别:客户端必须先发起 websocket 升级请求,然后服务器才能发送数据。

最大的区别在于,与 websockets 不同,HTTP/2 定义了自己的多路复用语义:流如何获取标识符以及帧如何携带它们所在流的 ID。 HTTP/2 还为流的优先级定义了流控制语义。这在 bidi 的大多数实际应用中都很重要。

(那个错误的文章还说Websocket标准有多路复用。不,它没有。其实并不难发现,只需打开Websocket RFC 6455并按⌘-F,然后输入“multiplex”。阅读后

The protocol is intended to be extensible; future versions will likely introduce additional concepts such as multiplexing.

你会发现Websocket多路复用有2013draft extension。但我不知道哪些浏览器(如果有的话)支持它。我不会尝试在该扩展的背后构建我的 SPA webapp,特别是随着 HTTP/2 的到来,支持可能永远不会到来)。

多路复用正是您通常在打开 bidi 的 websocket 时必须自己做的事情,例如,为响应式更新的单页应用程序提供动力。我很高兴它在 HTTP/2 规范中,一劳永逸。

想知道HTTP/2能做什么,看看gRPC就知道了。 gRPC 在 HTTP/2 中实现。具体查看 gRPC 提供的半双工和全双工流选项。 (请注意,gRPC 目前在浏览器中不起作用,但这实际上是因为浏览器 (1) 不会将 HTTP/2 框架暴露给客户端 javascript,并且 (2) 通常不支持预告片,用于 gRPC 规范。)

websockets 还能在哪里占有一席之地?最大的是服务器->浏览器推送的二进制数据。 HTTP/2 确实允许服务器->浏览器推送二进制数据,但它不会在浏览器 JS 中公开。对于像推送音频和视频帧这样的应用程序,这是使用 websockets 的原因。

编辑:2020 年 1 月 17 日

随着时间的推移,这个答案逐渐上升到顶部(这很好,因为这个答案或多或少是正确的)。然而,仍然偶尔会有评论说由于各种原因它是不正确的,通常与一些关于PUSH_PROMISE或如何在单页应用程序中实际消费面向消息的服务器-> 客户端推送的混淆有关。

如果你需要构建一个实时聊天应用程序,比方说,你需要向聊天室中所有打开连接的客户端广播新的聊天消息,你可以(而且可能应该)这样做没有网络套接字。

您将使用服务器发送事件向下推送消息,并使用 Fetch api to send requests up. Server-Sent Events (SSE) is a little-known but well supported API 公开面向消息的服务器到客户端流。尽管客户端 JavaScript 看起来不像它,但实际上您的浏览器(如果它支持 HTTP/2)将重用单个 TCP 连接来复用所有这些消息。没有效率损失,事实上它比 websockets 有优势,因为页面上的所有其他请求也共享相同的 TCP 连接。需要多个流?打开多个事件源!它们会自动为您复用。

除了比 websocket 握手更具资源效率和更少的初始延迟外,Server-Sent Events 还具有很好的 属性,它们会自动回退并在 HTTP/1.1 上工作。但是当你有一个 HTTP/2 连接时,它们工作得非常好。

这是一篇 real-world example 完成响应式更新 SPA 的好文章。

嗯,引用this InfoQ文章:

Well, the answer is clearly no, for a simple reason: As we have seen above, HTTP/2 introduces Server Push which enables the server to proactively send resources to the client cache. It does not, however, allow for pushing data down to the client application itself. Server pushes are only processed by the browser and do not pop up to the application code, meaning there is no API for the application to get notifications for those events.

因此 HTTP2 推送实际上是您的浏览器和服务器之间的东西,而 Websockets 确实公开了客户端(javascript,如果它在浏览器上的 运行)和应用程序都可以使用的 API用于传输实时数据的代码(运行 在服务器上)。

暂时到 2020 年 4 月,HTTP/2 不会让 WebSockets 过时。 WebSockets 相对于 HTTP2 的最大优势是

HTTP/2 works only on Browser Level not Application Level

意味着 HTTP/2 不提供任何 JS API 像 WebSockets 来允许通信和传输某种 JSON 或其他数据直接从应用程序(例如网站)到服务器。因此,据我所知,如果 HTTP/2 开始提供 API 之类的 WebSockets 来与服务器通信,它只会让 WebSockets 过时。直到它刚刚更新和更快的 HTTP 1.1 版本。

截至今天,没有。

HTTP/2,与HTTP相比,允许您与服务器保持连接。从那里,您可以同时拥有多个数据流。目的是即使没有客户端请求,您也可以同时推送多个内容。例如,当浏览器请求 index.html 时,服务器可能还想推送 index.cssindex.js。浏览器没有要求它,但服务器可能会在没有被询问的情况下提供它,因为它可以假设您在几秒钟后会想要。

这比获取 index.html 的 HTTP/1 替代方法更快,解析它,发现它需要 index.jsindex.css 然后 为这些文件构建 2 个其他请求。 HTTP/2 让服务器推送客户端甚至没有请求的数据。

在这种情况下,它与 WebSocket 类似,但并非设计使然。 WebSocket 应该允许 bi-directional 类似于 TCP 连接或串行连接的通信。这是一个相互通信的套接字。此外,主要区别在于您可以发送任何原始字节的任意数据包,而不是封装在 HTTP 协议中。 headers、路径、查询字符串等概念只在握手时发生,而WebSocket开辟了一个数据流。

另一个区别是您在 Javascript 中获得更多 fine-tuned 对 WebSocket 的访问权限,而使用 HTTP,它由浏览器处理。使用 HTTP 得到的只是 XHR/fetch() 中的任何内容。这也意味着浏览器将在您无法控制的情况下拦截和修改 HTTP headers(例如:OriginCookies 等)。此外,HTTP/2 能够推送的内容将发送到浏览器。这意味着 JS 并不总是(如果有的话)知道事情正在被推动。同样,对于 index.cssindex.js 是有意义的,因为浏览器会缓存它,但对于数据包就没有那么多了。

真是名副其实。 HTTP 代表超文本传输​​协议。我们围绕转移资产的概念进行调整。 WebSocket 是关于建立一个套接字连接,二进制数据在其中双向传递。


我们没有真正讨论的是 SSE(Server-Sent 事件)。将数据推送到应用程序 (JS) 不是 HTTP/2 的意图,但它是为了 SSE。 HTTP/2 使 SSE 得到了真正的加强。但当重要的是数据本身而不是到达的可变端点时,它并不是 WebSockets 的真正替代品。对于 WebSocket 中的每个端点,都会创建一个新的数据流,但是对于 SSE,它会在已经存在的 HTTP/2 session.

之间共享

这里总结了每个目标:

  • HTTP - 使用一项资产响应请求
  • HTTP/2 - 使用多个资产响应请求
  • SSE - 使用单向文本 (UTF-8) 事件流进行响应
  • WebSocket - 创建双向二进制数据流

不,WebSockets 并没有过时。但是,HTTP/2 破坏了为 HTTP/1.1 定义的 websockets(主要是通过使用升级 header 禁止协议更新)。这就是为什么这个 rfc:

https://datatracker.ietf.org/doc/html/rfc8441

为 HTTP/2 定义了一个 websocket 引导过程。