不支持/识别请求的 websocket 子协议时的 HTTP 响应代码

Posted

技术标签:

【中文标题】不支持/识别请求的 websocket 子协议时的 HTTP 响应代码【英文标题】:HTTP response code when requested websocket subprotocol isn't supported/recognized 【发布时间】:2012-11-24 20:49:12 【问题描述】:

将 HTTP 连接升级到 websocket 时,可以在可选的 HTTP 标头“Sec-WebSocket-Protocol”中提供一个或多个子协议。

如果服务器接受任何子协议,它会使用 HTTP 响应代码 101(“HTTP/1.1 101 切换协议”)进行响应,并包含指示所选子协议的 HTTP 标头“Sec-WebSocket-Protocol”。

但是服务器应该如何正确处理未知/不受支持的子协议呢?

这是否应该在 HTTP 连接“内”完成——通过使用一些 HTTP 响应代码?

或者是否应该将连接升级到 websocket - 并通过发送带有一些预定义 websocket 状态代码的“关闭帧”立即被服务器关闭?

RFC6455 是怎么说的?我无法得出结论。 现有的服务器实现如何处理它?

问候 /每/

【问题讨论】:

据我了解,第 4.2.2 节对此有一些信息:“如果服务器不希望同意建议的子协议之一 (...)”,但尚不完全清楚连接会发生什么。 【参考方案1】:

通过对 RFC 6455 的简要了解,我相信 WebSocket 子协议是可选的并且是经过协商的。在4.2.2 部分的“服务器要求”下:

   /subprotocol/
      Either a single value representing the subprotocol the server
      is ready to use or null.  The value chosen MUST be derived
      from the client's handshake, specifically by selecting one of
      the values from the |Sec-WebSocket-Protocol| field that the
      server is willing to use for this connection (if any).  If the
      client's handshake did not contain such a header field or if
      the server does not agree to any of the client's requested
      subprotocols, the only acceptable value is null.  The absence
      of such a field is equivalent to the null value (meaning that
      if the server does not wish to agree to one of the suggested
      subprotocols, it MUST NOT send back a |Sec-WebSocket-Protocol|
      header field in its response).  The empty string is not the
      same as the null value for these purposes and is not a legal
      value for this field.  The ABNF for the value of this header
      field is (token), where the definitions of constructs and
      rules are as given in [RFC2616].

如果服务器不同意与客户端使用子协议,则服务器不应发送值为“null”的子协议响应标头,并且客户端有责任在该点继续或终止连接。

【讨论】:

即使我认为在大多数情况下缺乏对子协议的支持会使升级到 websocket 的连接变得不必要,但这似乎是合理的。如果服务器建立了连接——表明它没有提供任何请求的子协议——就可以在客户端记录/处理它。 RFC 中的要点是子协议是一种协商扩展,很像 SSL 握手过程中的密码交换。这就是为什么应该在客户端终止连接的原因:如果客户端和服务器不支持公共子协议,他们显然无法通信,尽管服务器愿意为其他可能性保持连接打开。 是的,这是有道理的。我查看了浏览器的javascript Websocket API,并进行了一些快速测试。通过使用在建立连接时设置的只读“协议”参数,客户端可以处理不受支持的子协议情况。【参考方案2】:

WebSocket 的全部意义在于使用 WebSocket 运行从客户端到服务器的特定协议。但是客户端和服务器需要知道协议,以便两端都知道如何处理通过的 WS 消息。 WS 消息处理与您在 TCP 级别执行的操作没有什么不同。您不必使用协议字段,它仅在您想强制兼容性时才相关。

对于 Kaazing 服务器,我们提供了位于基本 websocket 层之上的特定协议库。您还可以在 Github 上找到各种协议库。除了握手之外,其他一切都是您使用 TCP 处理它的方式。您处理 websocket 消息并尝试解码协议。握手中的协议字段应该用于确保您的库实际上是匹配的协议库。因此,例如,如果我的服务器使用 STOMP,并且我尝试与我的客户端连接并且我想使用 STOMP,我的 STOMP 库应该检查协议字段以确保它匹配。端点可以按优先顺序指示,例如它可以说 AMQP 0.9 和 AMQP 1.0,如果两者都可用,将选择 AMQP 1.0。如果其中一个端点不使用另一端可以使用的任何协议,则它可以返回 null 并因此终止连接。

【讨论】:

以上是关于不支持/识别请求的 websocket 子协议时的 HTTP 响应代码的主要内容,如果未能解决你的问题,请参考以下文章

同时使用 HTTP 和 WebSockets 时的 API 命名约定

Apache CXF 中基于 WebSocket 的 SOAP?

前端面试题-WebSocket的实现和应用

天翼云CDN全站加速产品对websocket协议的支持

SpringBoot整合Websocket实现即时聊天功能

WebSocket小试牛刀