NodeJS回调函数 - 访问'res'

4

我正在使用Express框架,我的其中一个路由文件中有以下内容:

var allUsersFromDynamoDb = function (req, res) {
var dynamodbDoc = new AWS.DynamoDB.DocumentClient();
var params = {
    TableName: "users",
    ProjectionExpression: "username,loc,age"
};

dynamodbDoc.scan(params, function (err, data) {
    if (err) {
        console.error("Unable to query. Error:", JSON.stringify(err));
        res.statusCode = 500;
        res.send("Internal Server Error");
    } else {
        console.log("DynamoDB Query succeeded.");
        res.end(JSON.stringify(data.Items));
    }
});
}

我在我的一个路由中使用了上面的函数:
router.get('/users', allUsersFromDynamoDb);

现在,当我调用dynamodbDoc上的“scan”时定义的回调函数可以作为单独的函数非常有用。 我也可以将其重复使用在其他一些路由中。

但是,如何才能在此新函数中仍然访问“res”?

我认为我应该使用“闭包”,但我似乎无法完全正确地理解它。我认为我需要保持新回调函数的签名以期望2个参数,“err”和“data”,如以下页面所示:

http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#scan-property

对于如何完成这项工作有什么想法吗?


我认为只要回调函数在调用dynamodbDoc.scan的相同作用域内,你可以将回调函数放置在自己的命名函数中。由于JS的闭包特性,在这里,你的回调函数将能够访问与dynamodbDoc.scan相同的res对象。 - Soubhik Mondal
哦,是的,那是一个选项。我应该在我的问题描述中实际提到它。但如果我这样做,那么回调函数将不会在“allUserFromDynamoDB”函数之外可用。假设我有另一个函数(用于不同路由)“getSpecificUserFromDynamoDB”,我也想在那里使用它。希望我的意思清楚了。 - vksinghh
问题在于,如果回调函数在allUsersFromDynamoDb的范围之外定义,那么它将无法访问resreq对象。我认为你可以找到一个解决方法(具体取决于特定的用途)。 - Soubhik Mondal
2个回答

2
你可以将该函数作为中间件用于任何你想要的路由上。详情请参考http://expressjs.com/en/guide/using-middleware.html
使用中间件的新路由:
var middlewares = require('./middlewares'),
    controllers = require('./controllers');

router.get('/users', middlewares.allUsersFromDynamoDb, controllers.theRouteController);

中间件 (middlewares.js) 是将数据传递给 req,以便您可以在任何地方使用该数据的地方:

exports.allUsersFromDynamoDb = function (req, res, next) {
    var dynamodbDoc = new AWS.DynamoDB.DocumentClient();
    var params = {
        TableName: "users",
        ProjectionExpression: "username,loc,age"
    };

    dynamodbDoc.scan(params, function (err, data) {
        if (err) {
            console.error("Unable to query. Error:", JSON.stringify(err));
            next("Internal Server Error");
        } else {
            console.log("DynamoDB Query succeeded.");
            req.dataScan = JSON.stringify(data.Items);
            next();
        }
    });
};

最后是控制器(controllers.js)的部分:
exports.theRouteController = function (req, res) {
    // Here is the dataScan you defined in the middleware
    res.jsonp(req.dataScan);
};

感谢您的回答,Michelem!我真正希望做的是重用“function(err, data)”中的大部分代码,这样我就不必为其他路由重复编写它。我根据您使用中间件的建议做了一些事情,使事情变得更加清洁。我将在此处发布我所做的内容作为另一个答案,因为评论中的空间有限。 - vksinghh

1

根据Michelem的答案,我尝试了一些方法,使得代码更加简洁和可重用:

var allUsersFromDynamoDb = function (req, res, next) {
var dynamodbDoc = new AWS.DynamoDB.DocumentClient();
var params = {
    TableName: "users",
    ProjectionExpression: "username,loc,age"
};

dynamodbDoc.scan(params, function (err, data) {
    req.err = err;
    req.data = data;
    next();
});
}

现在我声明另一个函数:

var processUserResults = function (req, res, next) {
if (req.err) {
    console.error("Unable to query. Error:", JSON.stringify(req.err));
    res.statusCode = 500;
    res.send("Internal Server Error");
} else {
    console.log("DynamoDB Query succeeded.");
    res.end(JSON.stringify(req.data.Items));
}
};

最后,这个:
router.get('/users', [allUsersFromDynamoDb, processUserResults]); 

在原始的“function(err, data)”回调中,我需要做的只是始终设置2个值:
req.err = err
req.data = data

并调用next()。processUserResults同样适用于其他路由。

仍然好奇是否有其他高效的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接