【问题标题】:How to serve a Cramp::Websocket and a normal Rack app on the same port?如何在同一端口上提供 Cramp::Websocket 和普通 Rack 应用程序?
【发布时间】:2012-05-14 23:47:49
【问题描述】:

我正在尝试使用相同的端口通过Cramp(构建在 EventMachine 之上)使用 Ruby 1.9.3 和Thin 1.3.1 来提供正常的 HTTP 流量和 HTML5 websocket。这是一个最小的、独立的示例:

require 'thin'
require 'cramp'
require 'http_router'

Cramp::Websocket.backend = :thin

class SocketApp < Cramp::Action
  self.transport = :websocket

  on_start = :connected
  on_finish = :disconnected
  on_data = :message

  def connected
    puts 'Client connected'
  end
  def disconnected
    puts 'Client disconnected'
  end
  def message(msg)
    puts "Got message: #{msg}"
    render 'Here is your reply'
  end
end

class WebApp
  def call(env)
    [ 200, { 'Content-Type' => 'text/html' }, <<EOF
<html><head>
<script>
  function init() {
    function log(msg) { document.getElementById('log').innerHTML += msg + '<br>'; }
    var socketUri = 'ws://' + document.location.host + '/socket';
    log('Socket URI: ' + socketUri);
    var socket = new WebSocket(socketUri);
    socket.onopen = function(e) {
      log('onopen');
      socket.send('Is there anybody out there?');
      log('sent message');
    };
    socket.onclose = function(e) {
      log('onclose; code = ' + e.code + ', reason = ' + e.reason);
    };
    socket.onerror = function(e) {
      log('onerror');
    };
    socket.onmessage = function(e) {
      log('onmessage; data = ' + e.data);
    };
  }
</script>
</head><body onload='init();'>
  <h1>Serving Cramp::Websocket and normal Rack app on the same port</h1>
  <p id='log'></p>
</body></html>
EOF
    ]
  end
end

app = HttpRouter.new do
  add('/socket').to SocketApp
  add('/').to WebApp.new
end

run app

如果您想亲自尝试,请将此代码粘贴到名为 config.ru 的文件中并运行 thin start。您需要安装 gems thincramphttp_router

这个想法是 JavaScript 代码与ws://localhost:3000/socket 建立一个 WebSocket 连接,这会回显发送给它的消息,但这并没有按预期工作。 open 事件触发,发送消息时没有错误,但我们从未得到响应。

从服务器的角度来看,没有建立连接,因为Client connected 消息没有被打印出来。

使用thin start -D,我可以看到 HTTP 101 正在发生,并且正在交换一些二进制数据。

我做错了什么?

更新:如果我将文件分成两部分,撕掉HttpRouter,并在不同的端口上运行两个thin 实例,它仍然不起作用。所以问题出在套接字代码上,而不是在HttpRouterWebApp 上。

【问题讨论】:

    标签: ruby websocket rack thin cramp


    【解决方案1】:

    嗯,这是作弊,但我最终通过切换到不同的库来解决它:websocket-rack。对于好奇,更正的代码如下:

    require 'thin'
    require 'http_router'
    require 'rack/websocket'
    
    class SocketApp < Rack::WebSocket::Application
      def on_open(env)
        puts 'Client connected'
      end
      def on_close(env)
        puts 'Client disconnected'
      end
      def on_message(env, message)
        puts "Got message: #{message}"
        send_data 'Here is your reply'
      end
    end
    
    class WebApp
      def call(env)
        [200, { 'Content-Type' => 'text/html' }, <<EOF
    <html><head>
    <script>
      function init() {
        function log(msg) { document.getElementById('log').innerHTML += msg + '<br>'; }
        var socketUri = 'ws://' + document.location.host + '/socket';
        log('Socket URI: ' + socketUri);
        var socket = new WebSocket(socketUri);
        socket.onopen = function(e) {
          log('onopen');
          socket.send('Is there anybody out there?');
          log('sent message');
        };
        socket.onclose = function(e) {
          log('onclose; code = ' + e.code + ', reason = ' + e.reason);
        };
        socket.onerror = function(e) {
          log('onerror');
        };
        socket.onmessage = function(e) {
          log('onmessage; data = ' + e.data);
        };
      }
    </script>
    </head><body onload='init();'>
      <h1>Serving WebSocket and normal Rack app on the same port</h1>
      <p id='log'></p>
    </body></html>
    EOF
        ]
      end
    end
    
    app = HttpRouter.new do
      add('/socket').to(SocketApp.new)
      add('/').to(WebApp.new)
    end
    
    run app
    

    【讨论】:

      猜你喜欢
      • 2020-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-24
      • 2017-05-24
      • 2011-09-10
      • 2019-08-07
      • 1970-01-01
      相关资源
      最近更新 更多