学习如何使用Vandium这个开源npm模块,快速为Node.js应用程序添加验证和注入攻击保护,特别是在Amazon Web Services (AWS) Lambda环境中。在第一部分中,学习了如何使用Vandium包装AWS Lambda处理程序。处理程序本身由一系列嵌套的异步回调函数组成,用于从一个用户向另一个用户发送消息。
尽管这段代码是功能性的,但如果在未来添加新功能,可能不会那么容易维护。潜在问题出现的原因是代码结构开始呈现出Node.js世界中所谓的“回调地狱”。为了避免这种模式,JavaScript语言引入了Promises。
Promises的使用消除了回调地狱,同时提高了代码的可维护性和可测试性。让看看传统的Node.js回调模式:
doThisFirst('start', function(err, result) {
if (err) {
console.log(err);
return;
}
doThisSecond(result.two, function(err, result) {
if (err) {
console.log(err);
return;
}
doThisThird(result.three, function(err, result) {
if (err) {
console.log(err);
return;
}
console.log('result:', result);
});
});
});
上面的回调模式将被Promises替换,以同时减少代码量并提高代码的可读性。由于正在修改现有代码,不想改变库代码,可以使用优秀的bluebird库来“Promisify”代码。
现在,让看看如何将Promises应用于Lambda处理程序。
'use strict';
const vandium = require('vandium');
const bluebird = require('bluebird');
const tokenValidator = bluebird.promisifyAll(require('./lib/token-validator'));
const db = bluebird.promisifyAll(require('./lib/db'));
const msgService = bluebird.promisifyAll(require('./lib/messages'));
exports.handler = vandium(function(event, context, callback) {
return tokenValidator.validateTokenAsync(event.token)
.then(function(result) {
let senderId = result.userId;
return db.userExistsAsync(event.userId)
.then(function() {
return msgService.sendAsync(senderId, event.userId, event.message);
});
})
.then(function(result) {
callback(null, 'ok');
})
.catch(function(err) {
callback(err);
});
});
与之前的Promise示例一样,代码更加扁平化,更容易理解,代码量也减少了。注意在初始的“tokenValidator”Promise之后有一个嵌套的Promise。这样做是因为需要在确定用户存在之后访问“senderId”。当嵌套Promises时,内部Promise实例的返回值将被路由到外部实例的下一个“then”。
但有一件事感觉不太对劲?—?在Lambda处理程序的末尾使用回调函数来指示成功或失败的执行。理想情况下,Lambda处理程序将支持Promise模式,并允许在处理程序的末尾简单地返回一个值,而不是使用笨拙的回调函数。不幸的是,Lambda处理程序不支持Promises,但vandium支持。
Vandium专注于减少需要维护的代码量,同时提供鲁棒性、安全性和功能性。当使用vandium时,Promises被视为一等公民。要使用此功能,只需返回Promise,vandium会为处理其余的事情。
当vandium包装处理程序时,它会自动将成功和失败的Promise路由到回调处理程序。这很重要,因为它消除了开发人员手动将值路由到Lambda回调函数的每个成功或失败案例的需要。自然地,这允许开发人员更多地专注于编写Lambda处理程序中需要执行的实际逻辑。
以下是“Promisified”Lambda处理程序,用vandium包装,返回值(或错误)自动路由到Lambda回调。
'use strict';
const vandium = require('vandium');
const bluebird = require('bluebird');
const tokenValidator = bluebird.promisifyAll(require('./lib/token-validator'));
const db = bluebird.promisifyAll(require('./lib/db'));
const msgService = bluebird.promisifyAll(require('./lib/messages'));
exports.handler = vandium(function(event) {
return tokenValidator.validateTokenAsync(event.token)
.then(function(result) {
let senderId = result.userId;
return db.userExistsAsync(event.userId)
.then(function() {
return msgService.sendAsync(senderId, event.userId, event.message);
});
})
.then(function() {
return 'ok';
});
});
请注意,现在将Promise本身返回给vandium包装器。Vandium将负责确定Promise的结果。在成功完成的情况下,或者在错误的情况下,vandium将自动将任一结果的返回值路由回Lambda处理程序的回调函数。此外,代码通过移除不再需要的上下文和回调参数进一步简化。
从51行嵌套回调代码开始,现在只剩下不到40行代码,流程大大简化。代码行数更少,分支结构更简单,使得维护和测试更加容易。