如何设置RedisStore – Node,Express,Socket.io,Heroku

我正在使用部署在Heroku上的Node&Express 4.0,并且试图将Redis的Socket.io作为一个会话存储来实现。 所以我有这个作为我现在的代码:

var app = express(); var server = require('http').createServer(app); var io = require('socket.io').listen(server); var RedisStore = io.RedisStore; if (process.env.REDISTOGO_URL) { // inside if statement var rtg = require("url").parse(process.env.REDISTOGO_URL); var redis = require("redis").createClient(rtg.port, rtg.hostname); redis.auth(rtg.auth.split(":")[1]); } else { var redis = require("redis").createClient(); } /** Initialize RedisStore for socket.io **/ io.set('store', new RedisStore({ redis : redis })); 

但是我得到以下错误:

 14:25:03 web.1 | io.set('store', new RedisStore({ 14:25:03 web.1 | ^ 14:25:03 web.1 | TypeError: undefined is not a function 

我也看到了定义RedisStore的这种方式:

 var redis = require('socket.io/node_modules/redis'); var RedisStore = require('socket.io/lib/stores/redis'); 

不过,使用npm install --save socket.io安装的我安装的socket.io版本不包括lib目录中的stores

在这里输入图像描述


编辑

我在socket.io页面上看到了这个1.0版本的内容:

 // 2. Implement the socket.io-redis adapter var io = require('socket.io')(3000); var redis = require('socket.io-redis'); io.adapter(redis({ host: 'localhost', port: 6379 })); 

但是关于这个新模块没有其他文档可以find,而且由于我是新手,所以我不认为我可以自己解决这个问题。

node.js模块之间的趋势是删除不是模块真正核心的function。

这就是为什么socket.io 1.0不再支持开箱即用的redis。

所以第一步是追踪你需要的function。

  1. http://socket.io/docs/server-api/
  2. https://github.com/Automattic/socket.io-adapter
  3. https://github.com/Automattic/socket.io-redis

然后你需要安装其他模块npm install socket.io-redis --save

最后configuration你的应用程序。

 var app = express(); var server = require('http').createServer(app); var io = require('socket.io').listen(server); var redis = require('socket.io-redis'); io.adapter(redis(process.env.REDISTOGO_URL)); 

好的部分是socket.io-redis适配器接受redis的URL并默认为localhost:6379,所以你(应该)能够简单地通过REDISTOGO_URL

为了得到这个例子,我不得不parsing上面的库,所以我想我会张贴一个完整的例子,但我必须承认有几件事情,这使用REDISCLOUD,它是在Heroku,它的工作。 我会在其他地方发表,也可能把它放在一个文件。

 var redis = require('redis'); var ioredis = require('socket.io-redis'); //Adapter var url = require('url'); var redisURL = url.parse(process.env.REDISCLOUD_URL ); var pub = redis.createClient(redisURL.port, redisURL.hostname, {return_buffers: true}); var sub = redis.createClient(redisURL.port, redisURL.hostname, {return_buffers: true}); pub.auth(redisURL.auth.split(":")[1]); sub.auth(redisURL.auth.split(":")[1]); var redisOptions = { pubClient: pub, subClient: sub, host: redisURL.hostname, port: redisURL.port }; io.adapter(ioredis(redisOptions)); 

对于那些感兴趣的,这是我的原型聊天服务器运行在最新的socket.io与快递,多核心和Redis作为中间人。 无论是否连接到不同的节点和端口实例,广播消息都会发送给所有的房间用户。 赶紧跑

  • 节点server.js

和其他机器上

  • 节点client.js
  • 或者用于testing节点client.js 7001,7002,7003 ……

server.js

  var options = { //workers: 2, // total workers (default: cpu cores count). first_port: 7000, // 8000, 8001 are worker's ports (default: 8000). proxy_port: 5000, // default (5000). session_hash: function (req, res) { return req.connection.remoteAddress; }, no_sockets: false // allow socket.io proxy (default: false). }; require('sticky-socket-cluster')(options, start); function start(port) { // requirements var express = require('express'); var http = require('http'); var socketio = require('socket.io'); var path = require('path'); var sticky = require('sticky-session'); var app = express(); var server = http.createServer(app); var io = socketio.listen(server); var redis = require('socket.io-redis'); io.adapter(redis({ host: 'localhost', port: 6379 })); server.listen(port, function() { console.log(' - listening on ' + port+ ' ' + __dirname); }); // require our chatserver var ChatServer = require('./chatserver'); // initialize a new chat server. new ChatServer({io: io, port: port}).init(); } 

chatserver.js

 RoomUtil = (function(){ roomMessages = {}; return { getMessages : function(room_id,limit,cb){ //TODO cb(roomMessages[room_id] || []); }, postMessage : function(message,room_id,cb){ if (!roomMessages[room_id]) roomMessages[room_id] = []; roomMessages[room_id].push(message); cb(); } } })(); var Server = function(options) { var self = this; self.io = options.io; // users array self.users = []; // initialize function self.init = function() { console.log("init"); // Fired upon a connection self.io.on('connection', function(socket) { console.log("incoming connection"); // var ru = new RoomUser(); self.handleConnection(socket,options.port); }); } // socket handler for an incoming socket self.handleConnection = function(socket,port) { // wait for a login message socket.emit("incoming connection",{}); socket.on("joinroom",function(data,joinroom_callback){ console.log("attempt to join room ",data.room_id," on port ",port); if (!data.room_id){ console.log("cannon join room -> no room id given"); return socket.disconnect(); } else{ var room_id = data.room_id; socket.join(room_id,function(){ console.log(socket.rooms); RoomUtil.getMessages(data.room_id,50,function(messages){ console.log("client succesfully joined room ",data.room_id); joinroom_callback(null,{'messages':messages}); }); socket.on("login",function(data,login_callback){ if (!data.username){ login_callback("invalid userdata",null); } else{ login_callback(null,1); socket.on("post_message",function(data,message_callback){ if (!data.message || data.message == ""){ console.log("empty message posted. ignore"); message_callback("invalid_message",null); } else{ console.log("received message on port ",port,data.message); message_callback(null,1); RoomUtil.postMessage(data.message,room_id,function(){ RoomUtil.getMessages(room_id,50,function(messages){ console.log("emit messages to room id ",room_id); //socket.to(room_id).emit('update_messages', messages); //socket.broadcast.to(room_id).emit('update_messages', messages); //socket.broadcast.to(room_id).emit('update_messages', messages); //self.io.to(room_id).emit('update_messages', messages); self.io.in(room_id).emit('update_messages', messages); }); }) } }); } }); }); } }); } } module.exports = Server; 

client.js

 var servercon = 'http://localhost:'+(process.argv[2] || 5000); console.log("going to connect to "+servercon) var socket = require('socket.io-client')(servercon); var readline = require('readline'); var rl = readline.createInterface({ input: process.stdin, output: process.stdout }); socket.on('connect', function(){ console.log("connected, going to login"); socket.emit("joinroom",{"room_id":123123}, function(error,data){ if (error){ console.log("cannot join room ",error); } else{ console.log("succesfully joined room -> going to login now"); console.log("received messages count",data.messages.length); socket.emit("login",{username:"John Mckain"}, function(error, message){ if (error){ console.log("error logging in ",error); } else{ console.log("logged in succesfully -> post message now"); var readline = function(){ rl.question("type in a message -> ", function(message) { socket.emit("post_message",{'message':message}, function(error, message){ if (error){ console.log("error posting message"); readline(); } else{ console.log("succesfully posted message"); readline(); } }); }); } readline(); } }); socket.on("update_messages",function(data){ console.log("received new messages count ",data.length,data); }); } }); }); socket.on('event', function(data){ console.log("event send",data); }); socket.on('disconnect', function(e){ console.log("disconnected",e); }); socket.on("welcome",function(data){ console.log("on welcome ",data) }) socket.on("pong",function(e){ console.log("pong") }) 

以下代码适用于Heroku Redis,希望这有助于我。

 var app = express(); var server = require('http').Server(app); var io = require('socket.io')(server); var redis = require('redis'); var redisAdapter = require('socket.io-redis'); io.adapter(redisAdapter({ pubClient: redis.createClient(process.env.REDIS_URL, {return_buffers: true}), subClient: redis.createClient(process.env.REDIS_URL, {return_buffers: true}) }));