如何通过 websockets 在 ruby​​ on rails 和 reactJS 之间发送数据

Posted

技术标签:

【中文标题】如何通过 websockets 在 ruby​​ on rails 和 reactJS 之间发送数据【英文标题】:How to send data between ruby on rails and reactJS via websockets 【发布时间】:2017-05-04 12:44:43 【问题描述】:

我正在尝试制作一个应用程序,将 ruby​​ on rails 用于 backedn,将 reactjs 用于前端。我希望有几个人会同时使用这个应用程序,并且应用程序应该可以在不刷新页面或重定向到一些新路线的情况下运行(除了登录、注销、注册......)。对于后端和前端之间的通信,我正在尝试使用 websockets,但在终端和浏览器控制台中出现错误。两个错误每​​秒左右重复一次。

我在终端中遇到的错误是:

13:58:00 rails.1   | [ActionCable] [kvesic.mislav@gmail.com] Finished "/cable/" [WebSocket] for 127.0.0.1 at 2017-05-04 13:58:00 +0200
13:58:00 rails.1   | [ActionCable] [kvesic.mislav@gmail.com] There was an exception - NoMethodError(undefined method `fetch' for nil:NilClass)
13:58:00 rails.1   | [ActionCable] [kvesic.mislav@gmail.com] /home/mislav/.rvm/gems/ruby-2.3.0/gems/actioncable-5.0.2/lib/action_cable/server/configuration.rb:25:in `pubsub_adapter'
13:58:00 rails.1   | /home/mislav/.rvm/gems/ruby-2.3.0/gems/actioncable-5.0.2/lib/action_cable/server/base.rb:76:in `block in pubsub'
  ...
# here are now a lot of errors like :
13:58:00 rails.1   | /home/mislav/.rvm/gems/ruby-2.3.0/gems/actioncable-5.0.2/lib/action_cable/channel/streams.rb:106:in `block in stop_all_streams'
13:58:00 rails.1   | /home/mislav/.rvm/gems/ruby-2.3.0/gems/actioncable-5.0.2/lib/action_cable/channel/streams.rb:105:in `each'
13:58:00 rails.1   | /home/mislav/.rvm/gems/ruby-2.3.0/gems/actioncable-5.0.2/lib/action_cable/channel/streams.rb:105:in `stop_all_streams'
  ...
14:01:09 rails.1   | /home/mislav/.rvm/gems/ruby-2.3.0/gems/concurrent-ruby-1.0.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:319:in `block in create_worker'
14:01:10 rails.1   | Started GET "/cable" for 127.0.0.1 at 2017-05-04 14:01:10 +0200
14:01:10 rails.1   | Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2017-05-04 14:01:10 +0200
14:01:10 rails.1   | Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
14:01:10 rails.1   |   User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = 2 LIMIT $1  [["LIMIT", 1]]
14:01:10 rails.1   | [ActionCable] [kvesic.mislav@gmail.com] Registered connection (Z2lkOi8vYXV0b2Nvb3JkMy9Vc2VyLzI)
14:01:10 rails.1   | +++++++++++++ subscribed method

最后一行只是频道中订阅方法的 puts。它在那里,所以我可以跟踪数据流的方式

我在 chrome 控制台中遇到的错误是:

Uncaught TypeError: Cannot read property 'received' of undefined
    at t.notify (eval at <anonymous> (application.js:1187), <anonymous>:1:1715)
    at t.message (eval at <anonymous> (application.js:1169), <anonymous>:1:1778)

app/channels/users_channel.rb 如下所示:

class UsersChannel < ApplicationCable::Channel  
  def subscribed
    puts "+++++++++++++ subscribed method"
    stream_from 'users_channel'
  end

  def speak(data)
    puts "+++++++++++++++ speak method: #data"
    ActionCable.server.broadcast 'users_channel', message: data['message']
  end
end 

react 组件(组件名称为 )中获取数据并将数据发送到后端的部分如下所示:

...
  componentDidMount() 
    console.log("component did mount") //I see this in the console

    this.props.cable.subscriptions.create('UsersChannel', 
      message: "messsage",
      connected: function () 
        setTimeout(() => this.perform('speak',
          data: "some dataaaa"),
          1000);
      ,

      received: function(data) 
        console.log(data);
      
    );
  
...

在我的反应根文件中,我有:

...
import ActionCable from 'action-cable-react'

var actionCable = ActionCable.ActionCable
var cable = actionCable.createConsumer('ws://localhost:5000/cable');
console.log(cable)
/*
console.log(cable) outpust:

n url: "ws://localhost:5000/cable", subscriptions: t, connection: t, connectionMonitor: t
> connection: t
> connectionMonitor: t
> subscriptions: t
> url: "ws://localhost:5000/cable"
*/

  ...

  ReactDOM.render(
    <Application cable=cable />,
    document.getElementById('application')
  );

这是我第一次尝试使用 websockets,但我不知道发生了什么。我在***上搜索了一些关于这个主题的博文和问题,但我无法得到 这行得通。如果您能帮助我将一些数据从 rails cabel 和 console.log 一些数据放到浏览器中,我将不胜感激。

谢谢!

【问题讨论】:

这不是一个真正的答案,而只是一个建议:checkout ruby-hyperloop.io 您尝试做的所有事情都是开箱即用的,而且您可以用 ruby​​ 编写所有内容(客户端和服务器。)还有是一个活跃的 gitter 社区,gitter.im/ruby-hyperloop/chat 如果您需要帮助 我建议您查看 Ruby-on-Rails ActionCable 客户端。很像socket.io,ActionCable 通过 Websocket 连接实现通信协议,与原始 Web 套接字不同。您可以通过中间件(例如plezi)或其他解决方案将原始 Web 套接字与 RoR 结合使用。 【参考方案1】:

请参阅我上面的评论。由于需要大量调试,很难回答您的问题。但是,如果您不能使用http://ruby-hyperloop.io,那么我的建议是使用 pusher-faker 作为您的 websocket 传输。 (请参阅 pusher-faker gem)它易于设置,而且我发现诊断系统问题要容易得多。一切正常后,您可以切换回 action-cable。

我知道这不是一个很好的答案,但我会这样做:-)

【讨论】:

以上是关于如何通过 websockets 在 ruby​​ on rails 和 reactJS 之间发送数据的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 faye-websocket-ruby 向 websocket 客户端发送拒绝连接

ruby 中的安全 Websocket 客户端

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

用于 websocket-rails gem 的 Ruby websocket 客户端

ruby websocket_celluloid_server.rb

ruby websockets - HTML模板中的聊天示例