Rails WebSocket介绍
那道卡了一个学期的生产者消费者问题,今夏开工,和小新讨论了半天怎么怎么折腾,然后踩到了不少坑。
需要用到Java+Rails+JavaScript,题目要求,不得不用。Java用于生产者消费者模型,剩下的用于前端显示。
最初的设计是轮询,换句话说,类似于Java写入数据库,然后刷新定时刷新读写,一遍遍去查找更新,这样当然是可行的,但是——好Low。
现在我们有了一个更好的解决方案,用WebSocket实现动态的、即时的更新。当然当初知识一个小想法,WebSockeet对我还很抽象,所以咨询了一下用过的小伙伴小新,得知差不多一个意思,查了各种资料,开工。
WebSocket的原理性介绍:https://github.com/abbshr/abbshr.github.io/issues/22
简单的来说是在运输层用TCP来进行通讯,而不是用HTTP协议,这很好理解嘛,跟Socket差不多一个意思(本来以为这辈子都不会用Socket因为不搞桌面开发)。
所以依旧的被切成三段,前端<->Rails,Rails<->Java,因为目前Java部分我还不是很懂,虽然复制黏贴了HTTP请求的代码,但具体怎么写的看不懂,就不做说明了。
参考一下一篇教程:WebSocket on Rails 4 and Ruby 2
可以结合Wiki来看,因为光看他的有点不明不白,光看Wiki也不太明白。(Example需要Bootstrap2,需要自行引入)。
摸索了两天,总算觉得自己懂了点什么,记录一下。
###安装###
不用说,先在GemFile
里加上gem websocket-rails
,然后bundle
一下。
接下来运行rails g websocket_rails:install
,进行WebSocket的安装。
接着在config/environments/development.rb
里加入config.middleware.delete Rack::Lock
移除这个中间件。
所有的准备步骤就做完了。
###Controller###
1class ChatController < WebsocketRails::BaseController
2 def initialize_session
3 # perform application setup here
4 controller_store[:message_count] = 0
5 end
6end
7
看这个实例,非常简单的一个Example,需要注意的是它的父类是:WebsocketRails::BaseController
,而一般是ApplicationController
,这两个是不一样的,用做WebSocket的Controller是没法作为普通Controller进行访问的。
controller_store
之后进行解释。
那我们也别多说了,根据他的实例接着创建:
1def new_message
2 _message = {:message => 'this is a message'}
3 send_message :new_message, _message
4end
5
这里可能还无法理解,send_message
是一个内置的函数,它与broadcast_message
相对应,是用于给自己发送对象的,而broadcast_message
是广播,给所有连接者。
接下来我们顺势讲Event Router,你就能懂发生了什么了。
###Event Router###
在config里找到event.rb,加入
1subscribe :new_message, :to => ChatController, :with_method => :new_message
2
跟路由的语法很像,后面是Contrller以其对应的方法,那么前面自然是接下来我们要与前端向连的部分,叫做:new_message
,而刚刚在Controller里,也就是这么一个东西。
###JavaScript### 很快的我们可以来到前端了,很简单的Demo即将结束。
我们先链接服务器:var dispatcher = new WebSocketRails('localhost:3000/websocket');
,注意,在application.js
中,websocket对应的JS一定要先引入,否则会没有该类。
是否连通,我们可以测试一下:
1dispatcher.on_open = function(data) {
2 console.log('Connection has been established: ', data);
3 // You can trigger new server events inside this callback if you wish.
4}
5
这段代码在连接上之后立即执行,data由WebSocket提供,不用管。
测试通过之后我们可以接着来了。
1dispatcher.bind('new_message', function(data) {
2 console.log('Daso:', data.message);
3});
4
5
new_message
,也就是刚才:new_message
的部分,绑定一个事件,传入的是Object。
但是绑定不够,我们需要用trigger
触发:
1$('#hello').click(function(){
2 dispatcher.trigger('new_message');
3});
4
很简单的触发过程。
###普通的Controller### 普通的Controller建立,使用按钮,你就能感受到了。
###从前端发送消息###
力的作用是相互的,Event Router也是一个桥梁,前端调用trigger('event_name', {})
就能把数据传到后端,使用message[:xxx]
来访问。当然没有实验过/w\是看源代码感受到的。
###从一般的Controller中数据### 如果我们需要从HTTP协议获取数据,那么肯定会用到普通的Controller。
这里我们需要用到一个名叫Channels的东西,不复杂,甚至不需要你在Event Router里多写东西。
普通的Controller里加上一句
1WebsocketRails[:channel_name].trigger(:event_name, object_to_send)
2
接下来在js里新建Channels
1var channel = dispatcher.subscribe('channel_name');
2
3// You can also pass an object to the subscription event
4// var channel = dispatcher.subscribe({channel: 'channel_name', foo: 'bar'});
5
6// bind to a channel event
7channel.bind('event_name', function(data) {
8 console.log('channel event received: ' + data);
9});
10
触发同dispatcher,但需要注意的是,Channel的event只能由Channel触发,同理。
###Data Store###
Data Store有两种,上面我们或许已经见识过了——controller_store
和connection_store
。
connection_store
类似于Session
,是一个连接公用的数据。而controller_store
针对个体的不同Controller数据就不能互通了,这是他们俩最大的区别,一般我们用Session比较多,同理。
###结束### 剩下的,Wiki依旧不能丢,这么说起来WebSocket也不难的样子~
评论 (2)
大神我的rails是5.1.4,按照你的步骤来的,但是就是连接不上 this._conn = new WebSocket(this.url);这个地方报错 ,500 我是哪里没有注意到吗,请帮帮忙,谢谢
大神,我在集成这个,socket连接的时候总是报500错误