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

有没有计划淘汰websockets,代之以某种无头HTTP/2请求和服务器发起的推送消息?或者WebSockets将补充HTTP/2?


当前回答

答案是否定的。两者之间的目标是非常不同的。甚至有一个基于HTTP/2的WebSocket的RFC,它允许你在一个单一的HTTP/2 TCP管道上建立多个WebSocket连接。

通过减少打开新连接的时间,允许更多的通信通道,而不增加更多套接字、软irq和缓冲区的开销,HTTP/2上的WS将是一个资源节约的游戏。

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

其他回答

在读完RFC 7540之后,HTTP/2在所有用例中都使用了过时的websocket,除了将二进制数据从服务器推送到JS webclient。HTTP/2完全支持二进制bidi流(请继续阅读),但浏览器JS没有用于消费二进制数据帧的API,而且AFAIK也没有这样的API计划。

对于bidi流的其他应用,HTTP/2和websockets一样好,甚至更好,因为(1)规范为你做了更多的工作,(2)在许多情况下,它允许较少的TCP连接被打开到一个原点。

PUSH_PROMISE(通俗地称为服务器推送)不是这里的问题。这只是一个性能优化。

Websockets在浏览器中的主要用途是支持双向数据流。所以,我认为OP的问题是HTTP/2是否能更好地在浏览器中实现双向流,我认为是的,它是。

首先,它是bi-di。请阅读streams部分的介绍:

一个“流”是一个独立的、双向的帧序列 在HTTP/2连接中客户端和服务器之间交换。 流有几个重要的特征: 一个HTTP/2连接可以包含多个并发打开的连接 流,任一端点交错来自多个帧 流。 流可以单方面建立和使用,也可以由共享 客户端或服务器。 流可以被任意一个端点关闭。

像这样的文章(在另一个答案中有链接)在HTTP/2的这方面是错误的。他们说那不是比迪。看,有一件事是HTTP/2不能发生的:连接打开后,服务器不能启动常规流,只能启动推送流。但是一旦客户端通过发送请求打开了一个流,双方都可以在任何时候通过一个持久套接字发送数据帧- full bidi。

这与websocket没有太大区别:客户端必须在服务器发送数据之前发起一个websocket升级请求。

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

(那篇错误的文章还说Websocket标准有多路复用。不,它没有。这并不难找到,只需打开Websocket RFC 6455并按⌘-F,然后输入“multiplex”。读完之后

该协议是可扩展的;未来的版本可能会引入更多的概念,如多路复用。

你会发现2013年Websocket多路复用的扩展草案。但我不知道哪些浏览器支持这个功能。我不会尝试在这个扩展的背后构建我的SPA web应用程序,特别是随着HTTP/2的到来,支持可能永远不会到来)。

多路复用正是你在为bidi打开websocket时通常必须做的事情,比如说,为一个反应性更新的单页应用程序提供动力。我很高兴它在HTTP/2规范中,得到了一次性的解决。

如果你想知道HTTP/2能做什么,看看gRPC就知道了。gRPC是跨HTTP/2实现的。具体看一下gRPC提供的半双工和全双工流选项。(请注意,gRPC目前不能在浏览器中工作,但这实际上是因为浏览器(1)不会向客户端javascript公开HTTP/2框架,(2)通常不支持gRPC规范中使用的预告片。)

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

编辑时间:2020年1月17日

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

如果你需要构建一个实时聊天应用程序,比如说,你需要向聊天室中所有打开连接的客户端广播新的聊天消息,你可以(也可能应该)不需要websockets。

You would use Server-Sent Events to push messages down and the Fetch api to send requests up. Server-Sent Events (SSE) is a little-known but well supported API that exposes a message-oriented server-to-client stream. Although it doesn't look like it to the client JavaScript, under the hood your browser (if it supports HTTP/2) will reuse a single TCP connection to multiplex all of those messages. There is no efficiency loss and in fact it's a gain over websockets because all the other requests on your page are also sharing that same TCP connection. Need multiple streams? Open multiple EventSources! They'll be automatically multiplexed for you.

除了比websocket握手更有效的资源和更少的初始延迟之外,服务器发送事件还有一个很好的属性,它们自动返回并在HTTP/1.1上工作。但是当你有一个HTTP/2连接时,它们工作得非常好。

下面是一篇很好的文章,它提供了一个实现响应式更新SPA的真实示例。

引用InfoQ的一篇文章:

好吧,答案显然是否定的,原因很简单:正如我们上面所看到的,HTTP/2引入了Server Push,它使服务器能够主动地向客户端缓存发送资源。但是,它不允许将数据下推到客户机应用程序本身。服务器推送仅由浏览器处理,不会弹出到应用程序代码中,这意味着应用程序没有API来获取这些事件的通知。

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

消息交换和简单的流(不是音频,视频流)可以通过Http/2多路复用和WebSockets来完成。所以有一些重叠,但是WebSockets有很好的协议,很多框架/ api和更少的头开销。 这里有一篇关于这个主题的好文章。

不,WebSockets并没有过时。然而,HTTP/2打破了为HTTP/1.1定义的websocket(主要是通过禁止使用Upgrade报头进行协议更新)。这就是为什么这个rfc:

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

定义了HTTP/2的websocket引导过程。

答案是否定的。两者之间的目标是非常不同的。甚至有一个基于HTTP/2的WebSocket的RFC,它允许你在一个单一的HTTP/2 TCP管道上建立多个WebSocket连接。

通过减少打开新连接的时间,允许更多的通信通道,而不增加更多套接字、软irq和缓冲区的开销,HTTP/2上的WS将是一个资源节约的游戏。

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