Как вернуть json из функции обратного вызова в Lambda?

Я пытаюсь вернуть статус входа в систему из функции обратного вызова Cognito, которая написана в NodeJS Lambda. Однако, когда я вызываю 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 : '[email protected]'
  };

  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('[email protected]', 'H1%23$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('[email protected]', 'H1%23$4jsk', attributeList, null, function(err, result){

    // for testing purpose directly returning 
    return {
      statusCode: 500,
      body: JSON.stringify({
        status: 'FAIL',
        message: err.message
      })
    }

  })

};
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
5
0
8 094
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Это именно то, что говорится в сообщении об ошибке.

Все функции async возвращают промисы. module.exports.register = async (event, context, callback) => {}

Вы также используете обратный вызов, вызывая

callback(null, {
          statusCode: 500,
          body: JSON.stringify({
            status: 'FAIL',
            message: err.message
          }),
        });

Вместо использования обратного вызова просто верните либо ошибку, либо действительный ответ.

Спасибо за быстрый ответ, после того, как я удалил асинхронность, я не получаю никаких предупреждений. Однако он также ничего не возвращает, если просто вернуть его. Теперь я получаю [Serverless-Offline] Your λ handler 'register' timed out after 30000ms. Я даже пытался увеличить значение тайм-аута в файле YML, но все равно бесполезно. Любая причина ошибки?

FR STAR 01.04.2019 09:19

Я все еще изучаю Node, поэтому извините за нубский вопрос. Разве первый параметр в обратном вызове не должен использоваться для ошибок? В вашем примере первый параметр обратного вызова равен нулю, а затем ошибка.

KingAndrew 28.06.2020 17:27

Вы используете асинхронную функцию с обратным вызовом.

Попробуйте так:

Удалите обратный вызов из асинхронной функции.

async (event, context)

И измените возврат как:

if (err) {
      return {
          statusCode: 500,
          body: JSON.stringify({
            status: 'FAIL',
            message: err.message
          })
        }
      }

И поставьте await на вызов функции.

Пробовал, все равно получаю предупреждающее сообщение и ничего не возвращает.

FR STAR 01.04.2019 09:21
Ответ принят как подходящий

Ну ошибка точна. async оборачивает returnpromise. Либо используйте обратный вызов полностью, например:

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('[email protected]', 'H1%23$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. В другом месте вашего кода вы можете вызвать регистрацию, например:

var result = register();
result
  .then(data => console.info(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.info(result);
  } catch (err) {
  // reject from Promise
    console.error(err)
  }
}

Также обратите внимание, что здесь не требуется use strict, так как модули узлов используют strict по умолчанию.

Спасибо за подробный ответ, однако, когда я только что вернулся, я получаю сообщение об ошибке тайм-аута [Serverless-Offline] Your λ handler 'register' timed out after 30000ms. Я даже пытался увеличить значение тайм-аута в файле YML, но все равно бесполезно (см. мой код EDIT). когда я попробовал обратный вызов, он просто распечатал сообщение в командной строке. Я просто хочу вывести ответ JSON после успешного выполнения функции обратного вызова. Пример обещания, который вы продемонстрировали, работает нормально, однако, поскольку он блокирует, я не хочу его использовать. Любая идея, как я могу решить эту проблему?

FR STAR 01.04.2019 09:27
await равно blocking, так как выполнение приостанавливается. Если вы не хотите блокировки, используйте обратный вызов then для обещания, например somePromise.then(/*you can pass your callback function here*/() => //do something)
1565986223 01.04.2019 11:23

Другие вопросы по теме