【问题标题】:How to set RedisStore -- Node, Express, Socket.io, Heroku如何设置 RedisStore -- Node、Express、Socket.io、Heroku
【发布时间】:2016-08-31 04:36:30
【问题描述】:

我正在使用部署在 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 }));

但是我找不到关于这个新模块的其他文档,而且由于我是整个堆栈的新手,我想我自己无法弄清楚。

【问题讨论】:

  • Socket.io 版本? Socket.io 1.0 是最近发布的,并且有重大变化,所以很多信息已经过时了。

标签: node.js heroku express socket.io


【解决方案1】:

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

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

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

  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

最后配置您的应用程序。

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

【讨论】:

  • 好的。由于我真的迷失了所有这些,我将安装
  • 至少要开始,因为他们有很多好的 socket.io 0.8.x-0.9.x 教程等。 . .一旦你习惯了你想要升级的工作方式,也可以看看(听)nodeup.com/sixtyfour
  • 不幸的是,这对我不起作用,但@JeffAncel's 起作用了。
  • 如何从 Redis 存储中获取值?说得到redis.get("PHPREDIS_SESSION:" + handshakeData.sessionID, function (error, reply) {}
【解决方案2】:

我必须解析上面的库才能得到这个例子,所以我想我会发布一个完整的例子,但我必须承认有几件事是关闭的,它使用 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));

【讨论】:

  • 所以我正试图在我自己的实现中解决所有这些问题。查看此代码和下面的代码。由于您没有使用粘性会话,因此此处是否需要发布/订阅频道?下面的示例没有发布/订阅。似乎 pub/sub 会更稳定,因为在粘性会话中,一台服务器可能会出现故障并丢失该数据。
【解决方案3】:

以下代码适用于 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})
}));

【讨论】:

    【解决方案4】:

    对于感兴趣的人, 这是我在最新的 socket.io 上运行的原型聊天服务器,以 express、多核和 redis 作为中间体。 广播消息将发送给所有房间用户,无论他们是否连接到不同的节点和端口实例。 跑吧

    • 节点服务器.js

    在其他机器上

    • 节点客户端.js
    • 或用于测试节点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();
    }
    

    聊天服务器.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")
    })
    

    【讨论】:

    • 我在这个例子中看不到我们可以从 Redis 存储中读取数据并启动回调的部分。沿着redis.get("PHPREDIS_SESSION:" + handshakeData.sessionID, function (error, reply) { } 说一些话。是我吗?
    猜你喜欢
    • 2016-04-06
    • 2012-09-27
    • 2013-12-07
    • 1970-01-01
    • 2021-08-07
    • 1970-01-01
    • 1970-01-01
    • 2016-08-02
    • 2014-10-20
    相关资源
    最近更新 更多