【问题标题】:Node/Express route not waiting for Redis server callbackNode/Express 路由不等待 Redis 服务器回调
【发布时间】:2016-07-19 08:25:11
【问题描述】:

需要对下面的代码进行哪些具体更改,以便在对 Redis client.somecommand(..) 的任何打开调用返回之前不会发送 res.json(...) 命令?

下面的代码抛出与client.hmset(uname, { ... } 在调用res.json(...) 后尝试设置响应标头相关的错误。当我将 return res.json() 命令移到 client.exists(uname, function(err, reply) { ... } 条件块的末尾之后,而不是它们在块内的当前位置时,anonymous token 值将发送到客户端应用程序,而不是生成的 @987654332 @ 价值。这表明对 Redis 服务器的回调没有返回。

如何更改下面的代码,以使res.json( ... ) 命令在 Redis 服务器回调返回之前无法运行?理想情况下,如果 Redis 服务器回调花费的时间过长,在发送错误消息之前会有一些条件等待一段时间。

Redis 被添加到包含以下所有代码的routes.js 文件中,方法是在文件顶部添加以下两行:

var redis = require('redis');
var client = redis.createClient();

下面是对 Redis 服务器的各种调用:

client.exists(uname, function(err, reply) { ... }
client.hgetall(uname, function(err, object) { ... }
client.hmset(uname, { ... }
client.expire(uname, 10);

Node.js/Express.js API 路由的完整代码为:

app.get('/user**', function(req, res) {
    console.log("You Hit The User Route TOP");
    request({
        method: 'GET',
        url: authServer + '/uaa/user', 
        json: true, 
        auth: {
            user: null,
            password: null,
            sendImmediately: true,
            bearer: bearerToken 
        }
    }, function (error, response, body) {
        if(error){
          console.log('ERROR with user request.');
          return res.sendStatus(500);  
        }
        else {
            var uname = '';var jwtUser = 'empty';var jwtJSON = { "token" : "anonymous" }
            console.log(response.statusCode);
            if(body['name']){ 
                uname = body['name'];console.log('uname is: ');console.log(uname);
                if(uname.length > 0) {
                    scopesLocal = body['oauth2Request'].scope.toString();
                    client.exists(uname, function(err, reply) {//Check to see if a Redis key for the user already exists
                        if (reply === 1) {//a redis key DOES exist
                            console.log('\"'+uname+'\" exists');
                            client.hgetall(uname, function(err, object) {//retrieve all the values in the hash/object that we just set
                            if(object) {
                                if(object["jwt"]) { 
                                    console.log('object[\"jwt\"] is: ');console.log(object["jwt"]); 
                                    jwtJSON = { "token" : object["jwt"] };
                                    console.log('jwtJSON is: ');console.log(jwtJSON);
                                    return res.json(jwtJSON);
                                }
                            }
                        });
                        } else {//a redis key DOES NOT exist
                            console.log('\"'+uname+'\" doesn\'t exist');
                            jwtUser = generateJwt(uname, authoritiesLocal);
                            client.hmset(uname, {//store a hash/object
                                'AccessToken': body['details'].tokenValue,
                                'TokenType': body['details'].tokenType,
                                'Authenticated': body['authenticated'],
                                'Principal': body['principal'],
                                'Scopes': scopesLocal.toString(), 
                                'Authorities' : authoritiesLocal,
                                'jwt' : jwtUser
                            });
                            jwtJSON = { "token" : jwtUser };console.log('jwtJSON is: ');console.log(jwtJSON);
                            return res.json(jwtJSON);
                        }
                        client.expire(uname, 10);//set the key to expire in 10 seconds.  use this to manage session length
                    });//end of Redis conditional block
                    console.log('jwtJSON is: ');console.log(jwtJSON);
                } else { console.log('uname is empty!'); }
                return res.json(jwtJSON);
            }
        };
    });
    console.log("You Hit The User Route BOTTOM");
});

nodemon终端中的错误信息是:

_http_outgoing.js:346
    throw new Error('Can\'t set headers after they are sent.');
    ^

Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
    at ServerResponse.header (/home/user/nodejs_apps/oauth_seed_app/node_modules/express/lib/response.js:719:10)
    at ServerResponse.json (/home/user/nodejs_apps/oauth_seed_app/node_modules/express/lib/response.js:247:10)
    at Command.callback (/home/user/nodejs_apps/oauth_seed_app/app/routes.js:112:44)
    at normal_reply (/home/user/nodejs_apps/oauth_seed_app/node_modules/redis/index.js:714:21)
    at RedisClient.return_reply (/home/user/nodejs_apps/oauth_seed_app/node_modules/redis/index.js:816:9)
    at JavascriptRedisParser.Parser.returnReply (/home/user/nodejs_apps/oauth_seed_app/node_modules/redis/index.js:188:18)
    at JavascriptRedisParser.execute (/home/user/nodejs_apps/oauth_seed_app/node_modules/redis-parser/lib/parser.js:413:12)
    at Socket.<anonymous> (/home/user/nodejs_apps/oauth_seed_app/node_modules/redis/index.js:267:27)
    at emitOne (events.js:90:13)
    at Socket.emit (events.js:182:7)
    at readableAddChunk (_stream_readable.js:153:18)
    at Socket.Readable.push (_stream_readable.js:111:10)
    at TCP.onread (net.js:534:20)

我阅读了this posting 关于具体错误消息的信息。我阅读了this other posting 关于如何等待回调的信息。我还阅读了this posting 关于 Redis 对 Node 的回调。但我看不到如何将这些其他帖子的答案应用于上面代码中的 Redis 回调问题。

【问题讨论】:

    标签: javascript json node.js express redis


    【解决方案1】:

    问题在于 OP 中的 return res.json(jwtJSON); 命令没有被隔离到离散的 if...else 块中。

    解决办法是:

    if(something) {
        //populate jwtJSON with a real JWT
        return res.json(jwtJSON);
    } else {
        return res.json(jwtJSON);//this leaves the anonymous value
    }  
    

    对上述代码中的每个嵌套条件进行这种隔离可以解决问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-18
      相关资源
      最近更新 更多