使节点 Redis get() 同步

Posted

技术标签:

【中文标题】使节点 Redis get() 同步【英文标题】:Make Node Redis get() Synchronous 【发布时间】:2012-11-28 19:50:35 【问题描述】:

我刚刚开始使用 node 实现 redis。在实现身份验证方法期间,我需要检查令牌是否存在于 redis 中,如果不更新 redis 和我的 mongo db 中的新令牌,我需要编写一个大的回调块并且无法正确获取结果。我们怎样才能让 redis 得到回调的红色。我们怎样才能使它同步。示例代码如下。

module.exports.authenticate = function(request, response)   
    var reply = ;

    if(UserSchema)  
        var UserModel, attributes;

        /** Registering User Model; **/
        mongoose.model('user', UserSchema);
        UserModel = mongoose.model('user');

        attributes = request.params;

        UserModel.findOne(attributes, "_id name email token", function(error, user) 

            if(!error && user)  
                var token;

                //delete user.password;
                token = user.token;

                /** Checking token exists in redis; **/
                redisClient.get(token, function(error, value)   
                    if(value === null && error === null)    

                        /** Creating new token; **/
                        token = require('crypto').createHash('md5').update("" + (new Date()).getTime()).digest("hex");
                        user.token = token;

                        /** Storing new token on redis; **/
                        setTokenOnRedis(token);

                        /** Updating token in the user model; **/
                        UserModel.update( _id : user._id,  token : token , function(error, user)    
                            if(error !== null && user === null) 
                                deleteTokenOnRedis(token);

                                /** Error message; **/
                                reply = 
                                    error : true,
                                    code : "AUTH#001",
                                    msg : "User authentication failed, Please check user credentials."
                                
                                response.send(reply);

                            else if(error === null && user !== null)   
                                reply = user;
                                response.send(reply);
                            
                        );
                    else if(value !== null)    
                        reply = user;
                        response.send(reply);
                    else   
                        /** Error message; **/
                        reply = 
                            error : true,
                            code : "AUTH#001",
                            msg : "User authentication failed, Please check user credentials."
                        ;
                        response.send(reply);
                    
                );
            else   
                /** Error message; **/
                reply = 
                    error : true,
                    code : "AUTH#001",
                    msg : "User authentication failed, Please check user credentials."
                
                   
        );
    else   

        /** Error message; **/
        reply = 
            error : true,
            code : "AUTH#001",
            msg : "User authentication failed, Please check user credentials."
        

        response.send(reply);
    
;

【问题讨论】:

【参考方案1】:

不,您将无法同步任何 io 调用,包括 redis 调用。我知道的唯一可用的同步 io 调用是文件系统和控制台。

但是,您可以使用一些编码技术使异步编码更易于管理。

先检查错误,提前返回。 将重复代码移动到单独的函数中,例如创建错误结构。 使用这个异步库:https://github.com/caolan/async。特别是,瀑布函数在这里可能很方便。

我还认为您需要将这些函数传入一个回调方法,因为它们是异步的。

setTokenOnRedis(token); deleteTokenOnRedis(token);

我已经重构了您的示例代码,希望它的缩进更少,更易于阅读/维护。我没有使用异步,我将把它留给你。

就个人而言,我最初发现整个节点异步编码模型非常令人沮丧,但你已经习惯了。过了一段时间,你学会了使用各种异步编码模式,然后就可以忍受了:)

一些您可能会觉得有帮助的链接:

error handling in asynchronous node.js calls Node.js Best Practice Exception Handling How to avoid long nesting of asynchronous functions in Node.js

重构代码:

module.exports.authenticate = function(request, response)
  authenticate(request, response, function(err, reply)
    if(err)
       reply = authenticationError(err);
    
    response.send(reply);
  );
;

var authenticationError = function(internalmsg)
  return 
    internalmsg : internalmsg,
    error : true,
    code : "AUTH#001",
    msg : "User authentication failed, Please check user credentials."
  ;
;

var authenticate = function(request, response, callback)   
  if(UserSchema)  
    var UserModel, attributes;

    /** Registering User Model; **/
    mongoose.model('user', UserSchema);
    UserModel = mongoose.model('user');

    attributes = request.params;

    UserModel.findOne(attributes, "_id name email token", function(err, user) 
      if(err || !user)
        return callback(err || "UserModel.findOne, no user");
      

      var token;

      //delete user.password;
      token = user.token;

      /** Checking token exists in redis; **/
      redisClient.get(token, function(err, value)
        if(err)
          return callback(err);
        
        if(value)
          return callback(null, value);
        

        /** Creating new token; **/
        token = require('crypto').createHash('md5').update("" + (new Date()).getTime()).digest("hex");
        user.token = token;

        /** Storing new token on redis; **/
        setTokenOnRedis(token);

        /** Updating token in the user model; **/
        UserModel.update( _id : user._id,  token : token , function(err, user) 
          if(err || !user) 
            deleteTokenOnRedis(token);
            return callback(err || "UserModel.update, no user found");
          
          callback(null, user);
        );
      );
    );
  
;

【讨论】:

感谢您的折射代码。您绘制的点正是我正在寻找的。​​span> 【参考方案2】:

在最初的问题发生多年后,Node.js 的 Redis 客户端本质上仍然是异步的 - 并且不太可能改变。

但为了更方便地处理这种工作方式,该包支持承诺,如http://redis.js.org/#redis-a-nodejs-redis-client-usage-example-promises 所述。

它不会使 Node.js 和 Redis 客户端更加同步,但它是对注册回调函数的(小)改进,使您的代码更具可读性。

【讨论】:

以上是关于使节点 Redis get() 同步的主要内容,如果未能解决你的问题,请参考以下文章

Redis系列--主从同步

redis主从同步

当redis 主节点宕机重启以后,该节点不能跟选举后的master数据主从同步

Redis的同步机制

Redis学习 —— 主从同步

Redis高可用架构之主从同步