与Ruby和EM::WebSocket::Server的WebSocket握手



我正在尝试针对我的Rails应用程序用JavaScript创建一个简单的WebSocket连接。我得到以下信息:

到"ws://localhost:4000/"的WebSocket连接失败:WebSocket握手期间出错:"Sec WebSocket Accept"标头缺少

我做错了什么?这是我的代码:

JavaScript:

var socket = new WebSocket('ws://localhost:4000');
socket.onopen = function() {
  var handshake =
    "GET / HTTP/1.1n" +
    "Host: localhostn" +
    "Upgrade: websocketn" +
    "Connection: Upgraden" +
    "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==n" +
    "Sec-WebSocket-Protocol: quoten" +
    "Sec-WebSocket-Version: 13n" +
    "Origin: http://localhostn";
  socket.send(handshake);
};
socket.onmessage = function(data) {
  console.log(data);
};

Ruby:

require 'rubygems'
require 'em-websocket-server'
module QuoteService
  class WebSocket < EventMachine::WebSocket::Server
    def on_connect
      handshake_response =  "HTTP/1.1 101 Switching Protocolsn"
      handshake_response << "Upgrade: websocketn"
      handshake_response << "Connection: Upgraden"
      handshake_response << "Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=n"
      handshake_response << "Sec-WebSocket-Protocol: quoten"
      send_message(handshake_response)
    end
    def on_receive(data)
      puts 'RECEIVED: ' + data
    end
  end
end
EventMachine.run do
  print 'Starting WebSocket server...'
  EventMachine.start_server '0.0.0.0', 4000, QuoteService::WebSocket
  puts 'running'
end

握手头根据维基百科。

  1. 我认为,一旦连接打开,请求和响应就已经发生了,所以此时发送头已经太晚了。此外,页眉必须以一个空行结尾,您省略了这一行。

  2. 根据演示,您甚至不必在客户端或服务器中设置头——ruby模块自动处理服务器端的头,html5自动处理客户端的头。我认为这应该有效:

    要求";em-websocket服务器";

    class EchoServer<EM::WebSocket::服务器

    定义连接EM::WebSocket::Log.debug";"已连接";看跌期权;我感觉到了一种联系"结束

    定义接收消息看跌期权;收到:#{msg}"发送消息结束

    结束

    EM.run domyhost=";0.0.0.0";myport=8000看跌期权;正在启动WebSocket服务器。正在侦听端口#{myport}"EM启动服务器myhost、myport、EchoServer结束

html文件:

<!DOCTYPE html> <html> <head><title>Test</title>
<script type="text/javascript">
  var myWebSocket = new WebSocket("ws://localhost:8000");
  myWebSocket.onopen = function(evt)    { 
    console.log("Connection open. Sending message..."); 
    myWebSocket.send("Hello WebSockets!");       };
  myWebSocket.onmessage = function(evt)    { 
    console.log(evt.data);
    myWebSocket.close();   };
  myWebSocket.onclose = function(evt)    { 
    console.log("Connection closed.");    };
  myWebSocket.onerror = function(err)   {
    alert(err.name + " => " + err.message);   } </script>
</head> <body>   <div>Hello</div> </body> </html>

它确实适用于Safari 5.1.9(这是一款较旧的浏览器):我在服务器和客户端上都看到了预期的输出。然而,该代码在Firefox 21中不起作用:我收到错误消息。。。

Firefox can't establish a connection to the server at ws://localhost:8000/.
    var myWebSocket = new WebSocket("ws://localhost:8000");

我注意到,在Firebug和Safari Developer Tools中,服务器都不会发送Sec-WebSocket Accept标头:

Response Headers
Connection          Upgrade
Upgrade         WebSocket
WebSocket-Location  ws://localhost:8000/
WebSocket-Origin    null

Request Headers
Accept                  text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding         gzip, deflate
Accept-Language         en-US,en;q=0.5
Cache-Control           no-cache
Connection          keep-alive, Upgrade
DNT                 1
Host                    localhost:8000
Origin                  null
Pragma                  no-cache
Sec-WebSocket-Key   r9xT+ywe533EHF09wxelkg==
Sec-WebSocket-Version   13
Upgrade                 websocket
User-Agent          Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:21.0) Gecko/20100101 Firefox/21.0

我所尝试的一切都无法使代码在Firefox 21.0中工作。为了检查Firefox 21.0是否支持websocket,我去了:

http://www.websocket.org/echo.html  

它说我的浏览器确实支持websocket。

  1. 你有什么理由必须使用em-websocket服务器模块吗?github上对该模块的最后一次修改是在三年前。每当您在ruby代码中看到require rubygems时,都应该提醒您该代码已经过时。我尝试了较新的em websocket模块,并且能够在Firefox 21.0和Safari 5.1.9上使用websocket成功地来回传输数据:

    需要"em websocket"

    myhost=";0.0.0.0";myport=8000

    EM运行{看跌期权;正在侦听端口#{myport}"

    EM::WebSocket.run(:host=>myhost,:port=>myport,:debug=>do|ws|

     ws.onopen do |handshake|
       path = handshake.path
       query_str = handshake.query
       origin = handshake.origin
       puts "WebSocket opened:"
       puts "t path  tt -> #{path}" 
       puts "t query_str t -> #{query_str}"
       puts "t origin t -> #{origin}"
     end 
     ws.onmessage { |msg|
       ws.send "Pong: #{msg}"
     }
     ws.onclose {
       puts "WebSocket closed"
     }
     ws.onerror { |e|
       puts "Error: #{e.message}"
     }
    

    完}

客户端代码相同。现在,响应标头包括Sec-WebSocket-Accept:

Response Headers
Connection          Upgrade
Sec-WebSocket-Accept    LyIm6d+kAAqkcTR744tVK9HMepY=
Upgrade                 websocket

Request Headers
Accept  text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Cache-Control   no-cache
Connection  keep-alive, Upgrade
DNT 1
Host    localhost:8000
Origin  null
Pragma  no-cache
Sec-WebSocket-Key   pbK8lFHQAF+arl9tFvHn/Q==
Sec-WebSocket-Version   13
Upgrade websocket
User-Agent  Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:21.0) Gecko/20100101 Firefox/21.0

在您的代码中,我认为您没有设置任何标头。相反,您只是来回发送消息,而这些消息恰好包含看起来像标头的字符。显然,您的浏览器在允许连接之前,需要在响应中使用Sec-WebSocket-Accept标头,当em-WebSocket服务器模块未能在响应中设置该标头时,您的服务器将拒绝连接。

em-websockets服务器的相关源代码如下:

module EM
  module WebSocket
    module Protocol
      module Version76
      
        # generate protocol 76 compatible response headers
        def response
          response = "HTTP/1.1 101 Web Socket Protocol Handshakern"
          response << "Upgrade: WebSocketrn"
          response << "Connection: Upgradern"
          response << "Sec-WebSocket-Origin: #{origin}rn"
          response << "Sec-WebSocket-Location: #{scheme}://#{host}#{path}rn"
  
          if protocol
            response << "Sec-WebSocket-Protocol: #{protocol}rn"
          end
          response << "rn"
          response << Digest::MD5.digest(keyset)
          response
        end

正如您所看到的,它没有设置Sec-WebSocket-Accept标头。该代码位于一个名为Version76的模块中,在谷歌上搜索76版本的websockets会产生一个过时的协议(其中包含一个请求和响应的示例):

https://datatracker.ietf.org/doc/html/draft-hixie-thewebsocketprotocol-76

以下是当前的websockets协议(其中还包含一个请求和响应的示例):

https://www.rfc-editor.org/rfc/rfc6455

结论:em-websockets服务器已过时

相关内容

  • 没有找到相关文章

最新更新