AWS Lambda returns 'null' 经过 forEach 循环将多个文件保存在 s3 存储桶中

AWS Lambda returns 'null' after going through a forEach loop of saving multiple files in s3 bucket

我有一个 AWS Lambda 函数。它遍历数组列表,这是一个 URL 数组,并保存它们的屏幕截图并将它们放在 s3 中。我如何 return 此函数的输出是 screenshotLinks 数组,其中包含保存在 s3 中的文件的所有链接?最后还是用了回调函数,结果returns null!我想要回调函数输出保存在 screenshotLinks 数组中的所有 s3 文件链接。

exports.handler = (event, context, callback) => {

desktopLinks.forEach(function (url, index) {
      https.request(url, function(res) {
        var data = new Stream();
        res.on('data', function(chunk) {
          // Agregates chunks
          data.push(chunk);

        });

        res.on('end', function() {
          var body = data.read();
          // Once you received all chunks, send to S3
          var currentLink = links[index];
          var linkAddress = encodeURIComponent(currentLink);
          var slashPosition = getPosition(currentLink, '/', 3)+1;
          var linkName = currentLink.substr(slashPosition, currentLink.length)
          var params = {
            Bucket: bucket,
            Key: completeDate + '/screenshots/' + linkName + '.png',
            Body: body
          };
          s3.putObject(params, function(err, data, callback) {
            if (err) {
              console.error(err, err.stack);
            } else {
              bunch = params.Bucket + '/' + params.Key;
              screenshotLinks.push(bunch);
            }
          });
        });
        
      }).end();
     
  })
  callback(null, screenshotLinks)
};

您的代码是事件驱动/异步的,这意味着您在屏幕截图链接被填充之前调用回调。

节点 http.ClientRequest.end() 方法完成发送请求,但这并不意味着响应已被接收和处理,因为这是由异步事件处理程序完成的。然而,回调是在调用 request.end() 之后立即执行的,也就是在请求被触发之后,因此 screenshotLinks 是空的。

您需要从传递给 s3.putObject 的回调中执行回调。我建议您向回调传递一个 response/result 对象,该对象指示 putObject 是否成功并包含与之相关的 url 以及错误消息或屏幕截图链接,例如像这样:

      s3.putObject(params, function(err, data, callback) {
        var s3Response;
        s3Response.url = url;
        if (err) {
          s3Response.success = false;
          s3Response.error = err;
          console.error(err, err.stack);
        } else {
          bunch = params.Bucket + '/' + params.Key;
          s3Response.success = true;
          s3Response.screenshotLink = bunch;
        }
        callback(null, s3Response);
      });

我建议您使用 8.10 节点运行时。

参考:https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/

那么你的切入点应该是:

export async function <function_name>(event) {}

然后:

let s3 = new AWS.S3({ region: process.env.AWS_REGION, apiVersion: '2006-03-01' });
let params= 
{
     Bucket: /* a path to bucket (string) */,
     Key: name /* string */,
     Body: /* supported types (Buffer, Typed Array, Blob, String, ReadableStream) */,
     ACL: 'public-read',
     ContentType: 'image/png'
};

try
{
    let s3Response = await s3.upload(params).promise();
    // if succceed
    console.log(`File uploaded to S3 at ${s3Response.Bucket} bucket. File location: ${s3Response.Location}`);
}
catch (ex) // if error occured
{
    console.error(ex);
}