Rails 5 ActionCable WebSockets 未返回状态为 101 升级响应的升级标头 [英] Rails 5 ActionCable WebSockets is not returning upgrade headers with status 101 Upgrade response

查看:46
本文介绍了Rails 5 ActionCable WebSockets 未返回状态为 101 升级响应的升级标头的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

显示在最后,发现升级头实际上是创建的.

Shown at end, found that upgrade headers were actually created.

我正在使用 action-cable-example 代码库,尝试构建一个 WebSocket 应用程序.Chatty"应用程序依赖于应用程序中提供的浏览器客户端,运行良好.但是,我不打算使用该客户端,因为我需要外部 IoT 连接.因此,我正在尝试对外部非浏览器设备实施 ws/wss WebSocket 协议,我在 route.rb 中的连接是:

I'm working from the action-cable-example codebase, trying to build a WebSocket app. The "Chatty" application, which depends upon the browser client provided in the app, works fine. But, I am not going to use that client as I need an external IoT connection. As a result, I am trying to implement the ws/wss WebSocket protocols to external non-browser devices and my connection in route.rb is:

mount ActionCable.server => '/cable'

我尝试了几个外部客户端,例如 Chrome Simple WebSocket Client 扩展和 gem websocket-client-simple 使用 sample/client.rb.在这两种情况下,ActionCable 都不返回升级标头.Chrome 扩展程序抱怨如下:

I've tried several external clients, such as the Chrome Simple WebSocket Client extension and gem websocket-client-simple using sample/client.rb. In both cases, ActionCable returns no upgrade headers. The Chrome Extension complains as follows:

WebSocket connection to 'ws://127.0.0.1:3000/cable' failed: Error during WebSocket handshake: 'Upgrade' header is missing 

实际的握手表明这是真的,如:

The actual handshake shows that to be true, as in:

**General**
Request URL:ws://127.0.0.1:3000/cable
Request Method:GET
Status Code:101 Switching Protocols
**Response Headers**
view source
Connection:keep-alive
Server:thin
**Request Headers**
view source
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:Upgrade
Cookie:PPA_ID=<redacted>
DNT:1
Host:127.0.0.1:3000
Origin:chrome-extension://pfdhoblngboilpfeibdedpjgfnlcodoo
Pragma:no-cache
Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits
Sec-WebSocket-Key:1vokmzewcWf9e2RwMth0Lw==
Sec-WebSocket-Version:13
Upgrade:websocket
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36

根据标准,响应头是这样的:

Per the standards, the response headers are to be this:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

Sec-WebSocket-Accept 尤为重要,因为它是基于请求标头的 Sec-WebSocket-Key 进行的计算,以确认 ws/wss 已被理解并且应该发生交换协议.

The Sec-WebSocket-Accept is particularly important, as it's a calculation based on the request header's Sec-WebSocket-Key to confirm that ws/wss is understood and that the the Switching Protocols should occur.

在所有这些过程中,服务器更开心,直到客户端被勾选并关闭连接:

During all of this, the server is more happy, until the client gets ticked and closes the connection:

Started GET "/cable" for 127.0.0.1 at 2016-06-16 19:19:17 -0400
  ActiveRecord::SchemaMigration Load (1.0ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2016-06-16 19:19:17 -0400
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
Finished "/cable/" [WebSocket] for 127.0.0.1 at 2016-06-16 19:19:18 -0400

查看websocket-client-simple,我把返回给client.rb的WebSocket分解了,也显示空头.我先显示代码,然后显示 WebSocket:

Looking at websocket-client-simple, I broke down the WebSocket returned to client.rb, and it also showed empty headers. I am showing the code and then the WebSocket:

url = ARGV.shift || 'ws://localhost:3000/cable'
ws = WebSocket::Client::Simple.connect url

#<WebSocket::Client::Simple::Client:0x2cdaf68 
    @url="ws://localhost:3000/cable", 
    @socket=#<TCPSocket:fd 3>, 
    @handshake=<WebSocket::Handshake::Client:0x013231c8 
        @url="ws://localhost:3000/cable", 
        @headers={}, 
        @state=:new, 
        @handler=#<WebSocket::Handshake::Handler::Client11:0x2e88400 
            @handshake=<WebSocket::Handshake::Client:0x013231c8 
                @url="ws://localhost:3000/cable", 
                @headers={}, 
                @state=:new, 
                @handler=#<WebSocket::Handshake::Handler::Client11:0x2e88400 ...>, 
                @data="", 
                @secure=false, 
                @host="localhost", 
                @port=3000, 
                @path="/cable", 
                @query=nil, 
                @version=13>, 
            @key="KUJ0/C0rvoCMruW8STp0Sw==">, 
        @data="", 
        @secure=false, 
        @host="localhost", 
        @port=3000, 
        @path="/cable", 
        @query=nil, 
        @version=13>, 
    @handshaked=false, 
    @pipe_broken=false, 
    @closed=false, 
    @__events=[{:type=>:__close, :listener=>#<Proc:0x2d10ae8@D:/Bitnami/rubystack-2.2.5-3/projects/websocket-client-simple/lib/websocket-client-simple/client.rb:37>, :params=>{:once=>true}, :id=>0}], 
    @thread=#<Thread:0x2d10a70@D:/Bitnami/rubystack-2.2.5-3/projects/websocket-client-simple/lib/websocket-client-simple/client.rb:42 sleep>
>;

在此响应中,我注意到实例变量@handshaked"返回为 false.这可能是相关的,但到目前为止我还没有找到在代码中设置或引用的位置.

In this response, I noted the instance variable "@handshaked" is returned as false. That may be relevant, but I haven't found where that is set or referenced within the code so far.

更新:发现 WebSocket::Driver.start 实际上创建了升级标头.而且,@socket.write(response) 应该通过 EventMachine 将它们发送出去.代码:

UPDATE: Found that WebSocket::Driver.start actually creates the upgrade headers. And, @socket.write(response) should send them out through EventMachine. Code:

def start
  return false unless @ready_state == 0
  response = handshake_response
  return false unless response
  @socket.write(response)
  open unless @stage == -1
  true
end

handshake_response 是:

handshake_response is:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: iJVnsG1ApNMFzABXGDSHN1V0i/s=

推荐答案

问题是我试图在开发中使用瘦服务器.它会运作.但是,它实际上在处理过程中传输了响应头,例如:

The problem was that I was trying to use the Thin server in development. It would operate. However, it was actually transmitting the response headers during its processing, such as this:

Response Headers
Connection:keep-alive
Server:thin

ActionCable 实际上发送了适当的升级标头,但它是在 Thin 发送自己的标头后才这样做的,因此客户端无法识别它们.

ActionCable was actually sending the appropriate upgrade headers, but it was doing so only after Thin had sent out its own headers so the client didn't recognize them.

转换回 Puma 后,我按预期收到这些:

After converting back to Puma, I receive these as expected:

Response Headers
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: XJOmp1e2IwQIMk5n0JV/RZZSIhs=

这篇关于Rails 5 ActionCable WebSockets 未返回状态为 101 升级响应的升级标头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆