Rails 和 node.js 各有所长,Rails 在快速原型实现速度上远远比相对年轻的 node.js 快很多。大量的第三方库使得写 Rails 程序非常简单。但是在大量链接情况和实时应用的情况下编写 node.js 相对简单,尤其是有 socket.io/engine.io/sock.js 这些逆天的跨平台实时库。
在 Rails 2/3 的时期,如果不是大量使用客户端 Javascript,页面切换会较为频繁,使得 Socket.io 这种实时前端结构不是很好集成 - 每次页面切换都会造成 socket 断开重连。
Rails 4 引入了 Turbolinks,这个特性(库)有可能造成前端对象、内存泄漏,但是同样的,这个 Turbolinks 使得页面不再切换,socket.io 这种库不需要在页面跳转的时候重新连接了。
我刚刚做了一点小小的实验,完成了一个 Rails 4 + Turbolinks + socket.io 的原型,请大家提提意见。实现的功能很简单,/pages/create
动作可以发送广播信息,/pages/{new,recv}
接收广播信息,并且在 console 打出。
Rails 处理基本页面,使用 node.js 的 express 模块实现了一个反向代理服务器,为 Rails 提供代理。
结构如下
浏览器 <====> node.js (express + socket.io) <====> Rails
node.js 代码
var express = require('express');
var app = express();
var server = app.listen(3001);
var request = require('request');
var io = require('socket.io').listen(server);
app.use(express.bodyParser());
app.use('/broadcast', function (req, res) {
var data = req.body.data;
res.end();
io.sockets.emit('broadcast', data);
});
app.use('/', function(req, res) {
var url = "http://127.0.0.1:3000" + req.url;
var r = null;
if (req.method == 'POST') {
r = request.post({uri: url, json: req.body});
} else {
r = request(url);
}
req.pipe(r).pipe(res);
});
在application.html.erb
,</head>
之前加入 socket.io 相关代码
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect();
socket.on('broadcast', function (data) {
console.log(data);
});
</script>
最后,实现pages_controller.rb
的create
def create
content = params[:content]
Net::HTTP.post_form(URI('127.0.0.1:3001/broadcast'),
"data" => content,
)
redirect_to :action => :recv
end
测试打开两个窗口,一个窗口在 pages/recv
,一个窗口发送消息。最好的是接受窗口由于 Turbolinks 的作用,随意点击链接跳转都不会让 socket.io 重新链接。