【问题标题】:Cannot use Async/Await in a Serverless NodeJS Function无法在无服务器 NodeJS 函数中使用 Async/Await
【发布时间】:2022-01-07 12:21:57
【问题描述】:

我是使用 NodeJS 无服务器的新手,我正在尝试使用异步函数来散列密码并在数据库中执行一些操作,问题是当我声明函数异步时,我总是收到此错误:

但是如果我在这里删除 async 关键字:

module.exports.login = async (event, context, callback) => {

函数运行正常,但我当然不能在函数中使用 Promise。

这是一个端点,用于进行 API 调用。

这是我的代码:

'use strict';

require('dotenv').config({ path: './.env' });

const dataBase = require('./utils/db');
const bcrypt = require('bcrypt');

const encryptPassword = async (plainPassword) => {
   const saltRounds = 10;
   const hashedPassword = await bcrypt.hash(plainPassword, saltRounds);
   return hashedPassword;
};

module.exports.login = async (event, context, callback) => {
   context.callbackWaitsForEmptyEventLoop = false;
   const parsedBody = JSON.parse(event.body);
   const connect = dataBase.connectToDatabase();
   const newPassword = await encryptPassword('test');

   console.log(newPassword);

   connect.query('SELECT * FROM users', (error, results, fields) => {
      if (error) {
         console.error(error);
         callback(null, {
            statusCode: 500,
            body: JSON.stringify({
               error: JSON.stringify(error),
               message: 'Internal Server Error Booh!',
            }),
         });
      }
      if (results) {
         callback(null, {
            statusCode: 200,
            body: JSON.stringify({
               error: results,
               message: 'No Error',
            }),
         });
      }
   });
};

这里是我的数据库连接和配置:

db.js

const mysql = require('mysql');
const isDev = true;

// Create mySQL Connection
const connectToDatabase = () => {
   const pool = mysql.createPool({
      host: isDev ? process.env.DATABASE_HOST_DEV : process.env.DATABASE_HOST_PROD,
      user: isDev ? process.env.DATABASE_USER_DEV : DATABASE_USER_PROD,
      password: isDev ? process.env.DATABASE_PASSWORD_DEV : DATABASE_PASSWORD_PROD,
      database: isDev ? process.env.DATABASE_DATABASE_DEV : DATABASE_DATABASE_PROD,
      multipleStatements: true,
   });
   return pool;
};

exports.connectToDatabase = connectToDatabase;
exports.mysql = mysql;

我错过了什么?

编辑:

这一切的目的,是因为我正在学习无服务器。

所有这一切都将在 AWS Lambda 中结束,并带有一个使用 API Gateway 的端点。

因此,当您调用此端点时,您将发送一些参数来注册/登录到应用程序。

我需要使用async/await,因为如果你注册一个账户,密码需要经过哈希处理,然后存储到数据库中,或者如果你登录,则需要比较密码,这两个操作都是异步的。

这就是为什么我需要端点是一个异步函数。

编辑 2:

阅读这篇文章:https://github.com/netlify/netlify-dev-plugin/issues/160

正如 Phil 提到的,异步和回调不应该一起使用,所以我像这样修改了我的代码,同样的错误:

'use strict';

require('dotenv').config({ path: './.env' });

const dataBase = require('./utils/db');
const bcrypt = require('bcrypt');

const encryptPassword = async (plainPassword) => {
   const saltRounds = 10;
   const hashedPassword = await bcrypt.hash(plainPassword, saltRounds);
   return hashedPassword;
};

module.exports.login = async (event, context, callback) => {
   context.callbackWaitsForEmptyEventLoop = false;
   const parsedBody = JSON.parse(event.body);
   const connect = dataBase.connectToDatabase();
   const newPassword = await encryptPassword('test');

   console.log(newPassword);

   connect.query('SELECT * FROM users', (error, results, fields) => {
      if (error) {
         console.error(error);
         return {
            error: 'some error to test',
         };
      }
      if (results) {
         return {
            body: 'someBody',
         };
      }
   });
};

最终功能代码:

如果想知道如何将这些查询作为承诺,这是我的方法,希望它可以帮助那些在同样情况下苦苦挣扎的人。

'use strict';

require('dotenv').config({ path: './.env' });

const dataBase = require('./utils/db');
const bcrypt = require('bcrypt');

const encryptPassword = async (plainPassword) => {
   const saltRounds = 10;
   const hashedPassword = await bcrypt.hash(plainPassword, saltRounds);
   return hashedPassword;
};

module.exports.login = async (event, context, callback) => {
   context.callbackWaitsForEmptyEventLoop = false;
   const parsedBody = JSON.parse(event.body);
   const connect = dataBase.connectToDatabase();

   const hashedPassword = await encryptPassword('test');

   console.log(hashedPassword);

   return new Promise((resolve, reject) => {
      connect.query('SELECT * FROM users', (error, result) => {
         if (error) {
            reject(
               callback(null, {
                  statusCode: 500,
                  body: JSON.stringify({
                     error: JSON.stringify(error),
                     message: 'Internal Server Error Booh!',
                  }),
               })
            );
         }
         if (result) {
            resolve(
               callback(null, {
                  statusCode: 200,
                  body: JSON.stringify({
                     data: result,
                     message: 'No Error',
                  }),
               })
            );
         }
      });
   });
};

问候。

【问题讨论】:

  • encryptPassword 似乎不是异步的,那么您为什么要等待呢?如果有什么东西是异步的,那就是dataBase.connectToDatabase(),但你还没有显示那个代码
  • 你是对的,我已经更新了代码,哈希密码必须是一个异步/等待函数,同样的问题。
  • 这里的用例并不完全清楚 - 这是作为 api 在外部调用还是在应用程序内部调用?
  • 这将是一个 API 调用(它是一个端点),在外部。
  • 好的,谢谢 - 这被称为“无服务器”,但这只是一个架构决定 - 此代码旨在以任何方式在服务器上运行,因此没有轴承。你在使用 express 之类的框架吗?它可能有助于回答你想去哪里

标签: node.js aws-lambda async-await serverless


【解决方案1】:

快速查看the docs,看起来您不应该将asynccallback 参数混合使用。只使用其中一种,不要同时使用。

您可以迁移到 mysql2 库,这样您就可以使用 Promise 或坚持现有的并使用 encryptPassword("test").then() 而不是 await

// no async
module.exports.login = (event, context, callback) => {
  // remove this, you don't want it
  // context.callbackWaitsForEmptyEventLoop = false;

  const parsedBody = JSON.parse(event.body);
  const connect = dataBase.connectToDatabase();
  encryptPassword("test").then(newPassword => { // use .then()
    console.log(newPassword);

    // callback APIs are a pain, recommend migrating to mysql2 and use promises
    connect.query('SELECT * FROM users', (error, results, fields) => {
      if (error) {
        console.error(error);
        return callback(null, {
          statusCode: 500,
          body: JSON.stringify({
            error: JSON.stringify(error),
            message: 'Internal Server Error Booh!',
          }),
        });
      }
      callback(null, {
        statusCode: 200,
        body: JSON.stringify({
          error: results, // error?
          message: 'No Error',
        }),
      });
    }
  });
}

【讨论】:

  • 这工作正常,我认为这里真正的问题是 mysql 库。也许转向基于 Promise 的 API 是个好主意
猜你喜欢
  • 2020-05-02
  • 2018-10-13
  • 1970-01-01
  • 2019-02-17
  • 2018-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多