我有一个几天前写的lambda函数,在测试时表现得很好。在今天测试它之后(没有更改任何代码),我收到以下错误:"Invalid lambda function output : Invalid JSON"
.
下面是函数代码(Node.js 10.x):
const AWS = require("aws-sdk");
const joi = require("@hapi/joi");
const Cognito = new AWS.CognitoIdentityServiceProvider();
exports.handler = async (event) => {
// NOTE: Cognito expects Username to be the user's email
// Vars
const userPoolId = process.env.COGNITO_USER_POOL_ID;
const {email : UNSAFE_EMAIL, language : UNSAFE_LANGUAGE = "en-US"} = event;
// Normalize email and language
const UNSAFE_TRIMMED_EMAIL = UNSAFE_EMAIL.trim();
const UNSAFE_TRIMMED_LANGUAGE = UNSAFE_LANGUAGE.trim();
// Validate UNSAFE_INPUTS
const languageRegex = /^[a-z]{2}-[A-Z]{2}$/;
const schema = joi.object().keys({
email: joi.string().trim().email({minDomainSegments: 2}).required(),
language: joi.string().trim().min(2).max(5).regex(languageRegex).required()
});
const validationResult = joi.validate({
email: UNSAFE_TRIMMED_EMAIL,
language: UNSAFE_TRIMMED_LANGUAGE
}, schema);
if(validationResult.error) {
console.log(JSON.stringify(validationResult.error, null, 2));
return {
statusCode: 400,
body: JSON.stringify({
error: true,
error_message: "Invalid"
})
}
}
// Validation successful, change variable names to reflect
const VALIDATED_EMAIL = UNSAFE_TRIMMED_EMAIL;
const VALIDATED_LANGUAGE = UNSAFE_TRIMMED_LANGUAGE;
// Cognito params
// Username is the user's email
// email is also required in UserAttributes in order to send confirmation
// DesiredDeliveryMediums is required to send confirmation
const params = {
UserPoolId: userPoolId,
Username: VALIDATED_EMAIL,
UserAttributes: [
{
Name: "email",
Value: VALIDATED_EMAIL
},
{
Name: "custom:language",
Value: VALIDATED_LANGUAGE
}
],
DesiredDeliveryMediums: ["EMAIL"]
}
// Attempt to create user in Cognito
try {
const authRes = await Cognito.adminCreateUser(params).promise();
console.log("Success: ", JSON.stringify(authRes, null, 2));
return {
statusCode: 200,
body: JSON.stringify({
success: true
})
}
} catch(err) {
console.log("Error: ", JSON.stringify(err, null, 2));
return {
statusCode: 400,
body: JSON.stringify({
error: true,
error_message: err.message
})
}
}
};
在运行测试时,当传入格式不正确的事件数据时,我得到了预期的错误消息,并且当两次尝试使用相同的电子邮件创建用户时,我得到了Cognito错误。同样,这是预期的。然而,当传入一封有效的电子邮件,而用户池中没有用户时,我会得到以下响应(格式为可读性):
Response:
{
"statusCode": 400,
"body": {
"error": true,
"error_message": "Invalid lambda function output : Invalid JSON"
}
}
检查此函数连接到的Cognito用户池,我看到已经成功创建了一个用户。然而,没有电子邮件已经发送到电子邮件地址是发生在几天前。
所有记录的信息都是说我有一个无效的JSON错误,根本没有记录authRes
。当删除对Cognito的调用和相应的console.log
调用时,try块成功运行。所以问题在于对Cognito的调用。
但为什么这段代码在几天前还能完美工作的时候,今天却失败了呢?这就是让我非常沮丧的部分。
4条答案
按热度按时间k3bvogb11#
问题根本不是这个lambda函数。这是AWS的一个问题,我使用lambda函数作为Cognito用户池的自定义消息触发器。以下是出错的地方:
根据AWS文档,提供给自定义消息触发器lambda的事件数据具有以下形式,用于
adminCreateUser
函数调用:而且,从自定义消息触发器lambda返回的数据应该与事件的形式相同--只是
response
对象发生了变化。这就是我为lambda写的:
这在几天前测试时有效,因为事件对象是上面的形式。AWS偷偷地将
codeParameter
和usernameParameter
字段的内容更改为以下内容:因此lambda函数返回
null
,因为这些字符串没有通过验证-并且null
不是有效的JSON。所以临时的解决方法是验证这些新字符串。然而,这引起了一些关注。为什么AWS突然改变了事件对象,而没有更新文档?第二,我应该如何验证这些字符串在客户的电子邮件地址中注入是安全的?我知道我可以清理
usernameParameter
,但codeParameter
怎么样,因为它很可能包含危险的字符,如< > & ' "
,因为它是用随机符号生成的密码?如果自己生成密码,我可以确保它不会包含来自恶意行为者的数据,因此不需要进行清理。但是,如果它来自AWS,谁能说这些价值观不会受到损害呢?这就是为什么我首先添加了验证步骤,在这些值被更改的情况下应该失败。事实就是这样总之,我的所有代码都按预期运行。AWS在没有通知的情况下突然更改了他们的事件对象。
l7wslrjt2#
对我来说,我的一个同事正在尝试自定义授权器,因为这是我们在应用程序中需要采取的下一步。他取了一个与自定义授权无关的Lambda,并将其添加到Cognito用户池>常规设置>触发器>预身份验证和后身份验证字段中,以观察Lambda是否在CloudWatch中被触发,但随后没有将其从用户池中删除。
显然,lambda not 提供了任何类型的预/后授权,导致从Lambda发回的无效响应,导致“Invalid JSON”响应。
具体来说,开发人员控制台中收到的响应是“400 Bad Request”,响应为:
在我验证了没有人更改内置的Amplify身份验证lambda之后,这提示我在Cognito中进行了挖掘,这要归功于_new的答案。
3npbholx3#
我有一个类似的问题很长一段时间。我感到困惑的是,来自sam应用程序的一个lambda启动时没有问题,而另一个却给出了这样的错误。事实证明,您需要增加超时时间。默认超时为3秒。尝试将其增加到10秒或更长时间。我把它与20秒的差距,因为λ仍然死亡后执行
v6ylcynt4#
对我来说,这个问题是由于没有使用
async
函数作为处理程序造成的。我一添加async(或者只返回一个promise也可以),错误就消失了