#javascript #node.js #callback #aws-lambda #amazon-cognito
#javascript #node.js #обратный вызов #aws-lambda #amazon-cognito
Вопрос:
Я пытаюсь вернуть статус входа в систему из функции обратного вызова Cognito, которая записана в лямбде NodeJS. Однако, когда я вызываю API, ответ продолжает загружаться, и я получаю предупреждение об ошибке.
Вот мой код:
'use strict';
global.fetch = require('node-fetch');
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
module.exports.hello = async (event, context) => {
return {
statusCode: 200,
body: JSON.stringify({
message: "Hello there"
}),
};
// Use this code if you don't use the http event with the LAMBDA-PROXY integration
// return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};
module.exports.register = async (event, context, callback) => {
let poolData = {
UserPoolId : 'xxxxx', // Your user pool id here
ClientId : 'xxxxxxx' // Your client id here
} // the user Pool Data
let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
let attributeList = [];
let dataEmail = {
Name : 'email',
Value : 'test@gmail.com'
};
let dataName = {
Name : 'name',
Value : 'Jack'
};
var dataPhoneNumber = {
Name : 'phone_number',
Value : ' 94234324324234' // your phone number here with country code and no delimiters in front
};
let attributeEmail = new AmazonCognitoIdentity.CognitoUserAttribute(dataEmail);
let attributeName = new AmazonCognitoIdentity.CognitoUserAttribute(dataName);
var attributePhoneNumber = new AmazonCognitoIdentity.CognitoUserAttribute(dataPhoneNumber);
attributeList.push(attributeEmail);
attributeList.push(attributeName);
attributeList.push(attributePhoneNumber);
userPool.signUp('test@gmail.com', 'H1#$4jsk', attributeList, null, function(err, result){
let data = {};
if (err) {
callback(null, {
statusCode: 500,
body: JSON.stringify({
status: 'FAIL',
message: err.message
}),
});
} else {
let cognitoUser = result.user;
callback(null, {
statusCode: 200,
body: JSON.stringify({
status: 'SUCCESS',
message: '',
data: {
username: cognitoUser.getUsername(),
id: result.userSub
}
}),
});
}
})
// Use this code if you don't use the http event with the LAMBDA-PROXY integration
// return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};
Ошибка предупреждения следующим образом:
Serverless: Warning: handler 'register' returned a promise and also uses a callback!
This is problematic and might cause issues in your lambda.
Serverless: Warning: context.done called twice within handler 'register'!
бессерверный.yml
service: test-auth
plugins:
- serverless-offline
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: us-east-1
functions:
hello:
handler: handler.hello
events:
- http:
path: message
method: get
register:
handler: handler.register
events:
- http:
path: register
method: post
Любая помощь была бы оценена, заранее спасибо.
РЕДАКТИРОВАТЬ (2019-04-01):
module.exports.register = (event, context) => {
...
userPool.signUp('test@gmail.com', 'H1#$4jsk', attributeList, null, function(err, result){
// for testing purpose directly returning
return {
statusCode: 500,
body: JSON.stringify({
status: 'FAIL',
message: err.message
})
}
})
};
Ответ №1:
Это именно то, что указано в сообщении об ошибке.
Все async
функции возвращают обещания. module.exports.register = async (event, context, callback) => {}
Вы также используете обратный вызов, вызывая
callback(null, {
statusCode: 500,
body: JSON.stringify({
status: 'FAIL',
message: err.message
}),
});
Вместо использования обратного вызова просто верните либо ошибку, либо допустимый ответ.
Комментарии:
1. Спасибо за быстрый ответ, после того, как я удалил асинхронность, я не получаю никаких предупреждений. Однако, это также ничего не возвращает, если просто вернуть это. Теперь я получаю
[Serverless-Offline] Your λ handler 'register' timed out after 30000ms.
Я даже пытался увеличить значение тайм-аута в файле YML, но безрезультатно. Есть что-нибудь, вызывающее ошибку?2. Я все еще изучаю Node, поэтому, пожалуйста, извините за мой вопрос nube. Разве первый параметр в обратном вызове не должен использоваться для ошибок? В вашем примере первый параметр обратного вызова равен null, а затем ошибка.
Ответ №2:
Ну, ошибка точная. async
обертывает ваш return
с помощью promise
. Либо используйте обратный вызов до конца, как:
global.fetch = require('node-fetch');
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
// remove async
module.exports.register = (event, context, callback) => {
...
// if you're using callback, don't use return (setup your callback to be able to handle this value as required) instead do:
// calback({ message: 'Go Serverless v1.0! Your function executed successfully!', event })
// Use this code if you don't use the http event with the LAMBDA-PROXY integration
// return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};
Или не используйте обратный вызов, используйте async/await
( Promise
) до конца, как:
module.exports.register = async (event, context) => {
...
// needs promise wrapper, when using with promise, you might want to break up your code to be more modular
const mySignUp = (email, password, attributes, someparam) => {
return new Promise((resolve, reject) => {
userPool.signUp(email, password, attributes, someparam, function(err, result) {
let data = {};
if (err) {
reject({
statusCode: 500,
body: JSON.stringify({
status: 'FAIL',
message: err.message
}),
});
} else {
let cognitoUser = result.user;
resolve({
statusCode: 200,
body: JSON.stringify({
status: 'SUCCESS',
message: '',
data: {
username: cognitoUser.getUsername(),
id: result.userSub
}
}),
});
}
})
});
}
// call the wrapper and return
return await mySignUp('test@gmail.com', 'H1#$4jsk', attributeList, null);
// don't use double return
// Use this code if you don't use the http event with the LAMBDA-PROXY integration
// return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};
Теперь register
вернет promise
. В другом месте вашего кода вы можете вызвать register следующим образом:
var result = register();
result
.then(data => console.log(data))
// catches the reject from Promise
.catch(err => console.error(err))
or in async/await function (Note: `await` is valid only inside `async` function)
async function someFunc() {
try {
var result = await register();
// do something with result
console.log(result);
} catch (err) {
// reject from Promise
console.error(err)
}
}
Также обратите внимание, что use strict
здесь не требуется, поскольку модули узла по умолчанию используют strict.
Комментарии:
1. Спасибо за подробный ответ, однако, когда я просто возвращаюсь, я получаю ошибку тайм-аута
[Serverless-Offline] Your λ handler 'register' timed out after 30000ms.
Я даже пытался увеличить значение тайм-аута в файле YML, но безрезультатно (см. Мой код РЕДАКТИРОВАНИЯ). когда я попробовал обратный вызов, он просто напечатал сообщение в командной строке. Я просто хочу вывести ответ JSON после успешного выполнения функции обратного вызова. Продемонстрированный вами пример promise работает нормально, однако, поскольку он блокируется, я не хочу его использовать. Есть идеи, как я могу решить эту проблему?2.
await
blocking
поскольку это приостанавливает выполнение. Если вы не хотите блокировки, используйтеthen
обратный вызов для promise, напримерsomePromise.then(/*you can pass your callback function here*/() => //do something)
Ответ №3:
Вы используете асинхронную функцию с обратным вызовом.
Попробуйте это таким образом:
Удалите обратный вызов из асинхронной функции.
async (event, context)
И измените возвращаемое значение как:
if (err) {
return {
statusCode: 500,
body: JSON.stringify({
status: 'FAIL',
message: err.message
})
}
}
И поставьте await
на вызов функции.
Комментарии:
1. Пробовал, все еще получаю предупреждающее сообщение и ничего не возвращает.
Ответ №4:
Если это поможет кому-либо еще уловить это, вы можете добавить заголовки к возвращаемому:
return {
statusCode: 200,
headers: {"Content-Type": "application/json"},
body: JSON.stringify(response.data)
};