【问题标题】:How to return json from callback function within the Lambda?如何从 Lambda 中的回调函数返回 json?
【发布时间】:2019-08-21 14:36:48
【问题描述】:

我正在尝试从用 NodeJS Lambda 编写的 Cognito 回调函数返回登录状态。但是,当我调用 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%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'!

serverless.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%23$4jsk', attributeList, null, function(err, result){

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

  })

};

【问题讨论】:

    标签: javascript node.js callback aws-lambda amazon-cognito


    【解决方案1】:

    这正是错误消息的状态。

    所有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 文件中的超时值,但仍然没有用。任何导致错误的原因?
    • 我还在学习 Node,所以请原谅我的 nube 问题。回调中的第一个参数不应该用于错误吗?在您的示例中,第一个回调参数为 null,然后是错误。
    【解决方案2】:

    嗯,错误是准确的。 asyncpromise 包裹你的return。要么一直使用回调,比如:

    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%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.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在这里不是必需的,因为节点模块默认使用严格。

    【讨论】:

    • 感谢您的详细回复,但是当我刚返回时,我收到超时错误[Serverless-Offline] Your λ handler 'register' timed out after 30000ms. 我什至尝试增加 YML 文件中的超时值但仍然没有用(请参阅我的编辑代码)。当我尝试回调时,它只是在命令行中打印消息。我只想在回调函数成功后输出JSON响应。您演示的 Promise 示例运行良好,但是由于它阻止了我不想使用它。知道如何解决这个问题吗?
    • awaitblocking,因为它暂停执行。如果您不想阻塞,请使用then 回调作为somePromise.then(/*you can pass your callback function here*/() => //do something) 之类的promise
    【解决方案3】:

    您正在使用带有回调的异步函数。

    试试这个方法:

    从异步函数中移除回调。

    async (event, context)

    并将返回修改为:

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

    并在函数调用上加上await

    【讨论】:

    • 试过了,我仍然收到警告消息并且没有返回任何内容。
    猜你喜欢
    • 2018-01-07
    • 1970-01-01
    • 2015-08-27
    • 2017-10-14
    • 2018-11-27
    • 2018-07-23
    • 1970-01-01
    • 2016-11-17
    • 1970-01-01
    相关资源
    最近更新 更多