4

編集: 最後に表示され、アップグレード ヘッダーが実際に作成されたことがわかりました。

action-cable-exampleコードベースから作業して、WebSocket アプリを構築しようとしています。アプリで提供されるブラウザ クライアントに依存する「Chatty」アプリケーションは正常に動作します。ただし、外部 IoT 接続が必要なため、そのクライアントは使用しません。その結果、ws/wss WebSocket プロトコルを外部の非ブラウザー デバイスに実装しようとしています。route.rb での接続は次のとおりです。

mount ActionCable.server => '/cable'

Chrome Simple WebSocket Client 拡張機能や、 sample/client.rb を使用した gem websocket-client-simpleなど、いくつかの外部クライアントを試しました。どちらの場合も、ActionCable はアップグレード ヘッダーを返しません。Chrome 拡張機能は次のように文句を言います。

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

実際のハンドシェイクは、次のようにそれが真であることを示しています。

**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

標準に従って、応答ヘッダーは次のようになります。

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 が理解され、スイッチング プロトコルが発生する必要があることを確認するため、特に重要です。

このすべての間、クライアントがチェックされて接続を閉じるまで、サーバーはより満足しています。

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 を表示しています。

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 として返されることに注意しました。それは関連しているかもしれませんが、これまでのところ、コード内で設定または参照されている場所は見つかりませんでした。

更新: WebSocket::Driver.start が実際にアップグレード ヘッダーを作成することがわかりました。そして、@socket.write(response)はそれらを EventMachine 経由で送信する必要があります。コード:

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 は次のとおりです。

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

1 に答える 1

9

問題は、開発でシン サーバーを使用しようとしていたことです。それは動作します。ただし、実際には、処理中に次のような応答ヘッダーを送信していました。

Response Headers
Connection:keep-alive
Server:thin

ActionCable は実際には適切なアップグレード ヘッダーを送信していましたが、Thin が独自のヘッダーを送信した後にのみ送信したため、クライアントはそれらを認識しませんでした。

Puma に変換した後、期待どおりにこれらを受け取ります。

Response Headers
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: XJOmp1e2IwQIMk5n0JV/RZZSIhs=
于 2016-06-17T02:25:17.027 に答える