【问题标题】:Intermittent Error during WebSocket handshake: Unexpected response code: 400 on CloudBeesWebSocket 握手期间的间歇性错误:意外的响应代码:CloudBees 上的 400
【发布时间】:2014-01-24 23:29:57
【问题描述】:

我正在 CloudBees 上运行一个 websocket 应用程序 - 我间歇性地看到:

Error during WebSocket handshake: Unexpected response code: 400

我已经告诉它使用 http 1.1 允许通过以下方式升级:

bees app:proxy:update http_version=1.1

它有效,但我有时会看到错误(并非总是如此)。

【问题讨论】:

    标签: websocket cloudbees


    【解决方案1】:

    这几乎可以肯定是因为没有使用 https (SSL)。普通 http 上的 Websocket 容易受到在 http 层运行的中间代理(通常是透明的)破坏连接的攻击。

    这在蜂窝网络或办公室网络中很常见,这些网络可能使用多个无线连接和代理,该代理在连接之间传播 http 请求。

    避免这种情况的唯一方法是始终使用 SSL - 这为 websocket 提供了最佳工作机会。

    【讨论】:

      【解决方案2】:

      添加到 Michael Neale 的解决方案中。

      there 所述,截至 2013 年 10 月下旬,Play 本身不支持 WSS。

      所以简单地切换到 SSL 是行不通的。

      值得庆幸的是,在配置应用程序以使用 SSL 时,Cloudbees 将 Nginx 服务器设置为路由器,SSL 端点是路由器,因此there 描述的解决方法将起作用。

      因此,一旦您创建了自定义域名和相应的 Cloudbees 应用别名,在 Cloudbees 路由器中设置您的 SSL 证书,并将您的应用配置为使用该 Cloudbees 路由器,您就可以连接到 websocket。

      但是你必须强制 URL 是安全的,因为使用常规的 Play 路由解析器将不起作用。它们返回 ws://...,而不是 wss://... websockets URL。

      具体来说,以开箱即用的Play Framework sample Scala Websocket Chat app 为例:

      1. conf/routes 定义:

        GET /room/chat controllers.Application.chat(username)
        
      2. 应用定义:

        def chat(username: String) = WebSocket.async[JsValue] { request => ChatRoom.join(username) }
        
      3. chatRoom.scala.js 创建网络套接字:

        var WS = window['MozWebSocket'] ? MozWebSocket : WebSocket 
        var chatSocket = new WS("@routes.Application.chat(username).webSocketURL()") 
        

      这行不通,因为@routes....webSocketURL() 将返回 ws://,而不是 wss:// url。

      chatRoom.scala.js 可以进行如下修改,使其无论是在 https:// 还是 http:// 页面中运行都可以正常工作:

      var WS = window['MozWebSocket'] ? MozWebSocket : WebSocket; 
      var wsUrl = "@controllers.api.routes.PubSubController.chat(username).webSocketURL()"; 
      if(window.location.protocol == "https:") wsUrl = wsUrl.replace("ws:","wss:"); 
      var chatSocket = new WS(wsUrl);
      

      希望这会有所帮助。

      【讨论】:

      • 不应该 X-Forwarded-Proto 标头告诉 play 连接是安全的 - 并且在编写 url 时使用 wss?如果没有 - 我认为这是一个游戏错误。
      【解决方案3】:

      如果它是间歇性的,则可能是您的客户端库在一段时间后无法形成有效的握手。运行 Wireshark 以捕获包含 Connection: Upgrade 标头以验证握手请求是否有效的 HTTP 请求会提供有用的信息。

      有关如何发生这种情况的方法,请参阅subsection 4.2.1 of the WebSockets RFC 6455:

          The client's opening handshake consists of the following parts.  If
          the server, while reading the handshake, finds that the client did
          not send a handshake that matches the description below (note that as
          per [RFC2616], the order of the header fields is not important),
          including but not limited to any violations of the ABNF grammar
          specified for the components of the handshake, the server MUST stop
          processing the client's handshake and return an HTTP response with an
          appropriate error code (such as 400 Bad Request).
      

      【讨论】:

      • 很可能是 - 促成这种情况的具体案例是远程办公室中的某个人碰巧运行了 2 个蜂窝连接 - 有一些代理可以在它们之间取得平衡。 SSL 无论如何都在工作中 - 所以它可以帮助解决这个问题。我相信在这种情况下它是 chrome - 没有使用过的库。
      • 已经使用 WebSockets 部署了一些公共应用程序,wss:// 是必需的,尤其是对于美国的主要蜂窝运营商网络。 AT&T、Verizon、T-Mobile 网络可能不会在每条路由的任何地方都有 WebSocket 握手感知中介。 Chrome 似乎已经很好地实现了 WebSocket 规范,所以我肯定会倾向于这些网络问题。
      猜你喜欢
      • 1970-01-01
      • 2019-08-05
      • 2017-03-15
      • 1970-01-01
      • 2021-04-09
      • 1970-01-01
      • 2019-06-25
      • 1970-01-01
      • 2014-05-15
      相关资源
      最近更新 更多