HTTP/2使websockets过时了吗?

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

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

129913 次浏览

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

在HTTP/2中,服务器推送(server-push)在后台使用,以改善客户端从浏览器加载资源的情况。作为一名开发人员,你在开发过程中并不会真正关心它。然而,使用Websocket,开发者可以使用API,它可以使用唯一的全双工连接来消费和推送消息。

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

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

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

即(来自HTTP2草案):

中介可以接收来自服务器并且选择不转发给客户的推送。换句话说,如何利用推送的信息取决于中介。同样,中介可能选择向客户端进行额外的推送,而不需要服务器采取任何操作。

因此,HTTP/2 Push不能取代WebSockets。

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

的确,该标准规定:

HTTP/2连接是持久的。为了获得最佳性能,预期客户端不会关闭连接,直到确定不需要与服务器进行进一步的通信(例如,当用户导航离开特定的网页时)或直到服务器关闭连接。

但是…

如果必要的话,鼓励服务器尽可能长时间地保持打开连接但是允许终止空闲连接。当任何一个端点选择关闭传输层TCP连接时,终止端点应该首先发送一个超时帧(章节6.8),以便两个端点可以可靠地确定之前发送的帧是否已经处理,并优雅地完成或终止任何必要的剩余任务。

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

网页也不能在关闭后重新启动HTTP/2连接(除非我们又回到了长时间拖拉的状态)。

EDIT(2017,两年后)

HTTP/2的实现表明,多个浏览器选项卡/窗口共享一个HTTP/2连接,这意味着push将永远不知道它属于哪个选项卡/窗口,从而消除了使用push替代Websockets的情况。

编辑(2020)

我不知道为什么人们开始对答案投反对票。如果说有什么不同的话,那就是从最初的答案发布到现在的几年证明了HTTP/2不能取代WebSockets,而且它的设计初衷也不是这样的。

当然,HTTP/2可能被用于隧道 WebSocket连接,但这些隧道连接仍然需要WebSocket协议,它们将影响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

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

在刚刚读取完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。请阅读流部分的介绍:

< p >“stream"是独立的、双向的帧序列吗 在HTTP/2连接中客户端和服务器之间交换。 流有几个重要的特征:

一个HTTP/2连接可以包含多个并发打开 流,任一端点交错来自多个帧 流。< / p >

流可以单方面建立和使用,也可以由

.

.

.

流可以被任意一个端点关闭。

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

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

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

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

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

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

编辑时间:2020年1月17日

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

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

你可以使用服务器发送事件向下推送消息,使用获取 api向上发送请求。服务器发送的事件 (SSE)是一个鲜为人知的良好的支持 API,它公开了一个面向消息的服务器到客户端流。尽管在客户端JavaScript看来不是这样,但实际上浏览器(如果它支持HTTP/2)将重用单个TCP连接来复用所有这些消息。这并没有效率上的损失,事实上,它比websockets有好处,因为你页面上的所有其他请求也共享同一个TCP连接。需要多个流?打开多个EventSources!它们会自动多路复用。

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

这里有一篇很好的文章,用现实的例子实现了响应式更新SPA。

好吧,引用这InfoQ文章:

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

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

到2020年4月为止,HTTP/2还没有淘汰WebSockets。WebSockets相对于HTTP2的最大优势是

HTTP/2 works only on Browser Level not Application Level

意味着HTTP/2不提供任何像WebSockets那样的JS API来允许通信和直接从应用程序(例如网站)向服务器传输某种JSON或其他数据。所以,就我所相信的,只有当HTTP/2开始提供类似WebSockets的API来与服务器通信时,WebSockets才会被淘汰。在此之前,它只是更新和更快的HTTP 1.1版本。

到今天为止,还没有。

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

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

在这种情况下,它类似于WebSocket,但在设计上并不是这样。WebSocket应该允许类似于TCP连接或串行连接的双向通信。它是两者相互通信的套接字。此外,主要的区别是,您可以发送任何原始字节的任意数据包,而不是封装在HTTP协议中。头、路径、查询字符串的概念只在握手期间发生,但是WebSocket打开了一个数据流。

另一个不同之处在于,你可以在Javascript中对WebSocket进行更多的微调访问,而在HTTP中,它是由浏览器处理的。你用HTTP得到的只是你能在XHR/fetch()中找到的东西。这也意味着浏览器将在你无法控制的情况下拦截和修改HTTP标头(例如:OriginCookies等)。此外,HTTP/2能够推送的内容会被发送到浏览器。这意味着JS并不总是(如果有的话)知道东西正在被推送。同样,这对index.cssindex.js是有意义的,因为浏览器会缓存它,但对数据包就没有那么多了。

一切都在于名字。HTTP代表超文本传输协议。我们围绕着资产转移的概念。WebSocket是关于构建一个套接字连接,其中二进制数据可以双向传递。


我们没有真正讨论的是SSE(服务器发送事件)。将数据推送到应用程序(JS)不是HTTP/2的意图,但它是SSE的目的。SSE在HTTP/2中得到了真正的加强。但当重要的是数据本身,而不是到达的变量端点时,它并不是WebSockets的真正替代品。对于WebSocket中的每个端点,都会创建一个新的数据流,但是对于SSE,它会在已经存在的HTTP/2会话之间共享。


以下是每项目标的总结:

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

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

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

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

没有HTTP/2不会使websocket过时,但是上交所HTTP / 2上提供了一个可行的替代方案。需要注意的是SSE不支持从服务器到客户端的未经请求的事件(HTTP/2也不支持):即客户端必须通过创建EventSource实例指定事件源端点来显式订阅。因此,您可能不得不重新组织客户端如何安排要交付的事件(我想不出这实际上是一个技术障碍的场景)。

SSE使用HTTP/1.1。但是HTTP/2使得SSE在效率方面与websockets普遍可行并具有竞争力,而不是实际上无法使用。首先,HTTP/2将多个事件源连接(HTTP/2术语中的或者更确切地说“溪流”;)多路复用到单个TCP连接上,而在HTTP/1.1中,每个连接都需要一个连接。根据HTTP/2 规范,默认情况下每个连接可以创建数百万个流,推荐的(可配置的)最小值为100,其中浏览器可能会极度的有限它们可以建立的TCP连接的数量。第二个原因是效率:HTTP/2中的许多流所需的开销比HTTP/1.1中所需的许多连接要少得多。

最后一件事是,如果你想用SSE取代websockets,你就放弃了一些构建在websockets之上的工具/中间件。我特别想到socket . io(这是很多人实际使用websocket的方式),但我相信还有很多。