Node.js 从URL获取图像到S3

Node.js 从URL获取图像到S3,node.js,amazon-web-services,amazon-s3,aws-lambda,Node.js,Amazon Web Services,Amazon S3,Aws Lambda,目标是让AWS lambda每天将特定的jpg从URL复制到S3存储桶。这似乎是一个超级简单的lambda函数,但它不起作用。我将此设置作为本地NPM项目,然后在AWS lambda控制台中上载压缩文件。下面的代码运行时没有错误,但不会复制图像。任何帮助都将不胜感激 "use strict"; const AWS = require("aws-sdk"); const Jimp = require("jimp"); const s3 = new AWS.S3(); const imageTyp

目标是让AWS lambda每天将特定的jpg从URL复制到S3存储桶。这似乎是一个超级简单的lambda函数,但它不起作用。我将此设置作为本地NPM项目,然后在AWS lambda控制台中上载压缩文件。下面的代码运行时没有错误,但不会复制图像。任何帮助都将不胜感激

"use strict";

const AWS = require("aws-sdk");
const Jimp = require("jimp");
const s3 = new AWS.S3();
const imageType = "image/jpeg";
const bucket = 'mybucket';

exports.handler = (event, context, callback) => {
    let objectKey = 'myimage.jpg';

    Jimp.read('sampleURL.com/image.jpg')
    .then(image => {
        s3.putObject({
            Bucket: bucket,
            Key: objectKey,
            Body: image,
            ContentType: imageType
        })
    })
    .catch(err => {
        // Handle an exception.
    });


};

aws cloudwatch日志

2019-10-24T12:48:23.105Z    bac7d80e-5544-4ea5-ae12-478281338389    INFO    { Error: Could not find MIME for Buffer <null>
    at Jimp.parseBitmap (/var/task/node_modules/@jimp/core/dist/utils/image-bitmap.js:120:15)
    at Jimp.parseBitmap (/var/task/node_modules/@jimp/core/dist/index.js:506:32)
    at /var/task/node_modules/@jimp/core/dist/index.js:448:15
    at /var/task/node_modules/@jimp/core/dist/index.js:176:14
    at /var/task/node_modules/@jimp/core/dist/request.js:66:9
    at IncomingMessage.<anonymous> (/var/task/node_modules/phin/lib/phin.compiled.js:1:2100)
    at IncomingMessage.emit (events.js:203:15)
    at IncomingMessage.EventEmitter.emit (domain.js:448:20)
    at endReadableNT (_stream_readable.js:1145:12)
    at process._tickCallback (internal/process/next_tick.js:63:19) methodName: 'constructor' }
END RequestId: bac7d80e-5544-4ea5-ae12-478281338389
REPORT RequestId: bac7d80e-5544-4ea5-ae12-478281338389  Duration: 612.63 ms Billed Duration: 700 ms Memory Size: 128 MB Max Memory Used: 97 MB  Init Duration: 557.69 ms    
2019-10-24T12:48:23.105Z bac7d80e-5544-4ea5-ae12-478281338389信息{错误:找不到缓冲区的MIME
在Jimp.parseBitmap(/var/task/node_modules/@Jimp/core/dist/utils/image-bitmap.js:120:15)
在Jimp.parseBitmap(/var/task/node_modules/@Jimp/core/dist/index.js:506:32)
at/var/task/node_modules/@jimp/core/dist/index.js:448:15
at/var/task/node_modules/@jimp/core/dist/index.js:176:14
at/var/task/node_modules/@jimp/core/dist/request.js:66:9
输入消息时。(/var/task/node_modules/phin/lib/phin.compiled.js:1:2100)
在IncomingMessage.emit(events.js:203:15)
在IncomingMessage.EventEmitter.emit(domain.js:448:20)
在endReadableNT(_stream_readable.js:1145:12)
在进程中。_tickCallback(internal/process/next_tick.js:63:19)methodName:'constructor'}
结束请求ID:bac7d80e-5544-4ea5-ae12-478281338389
报告请求ID:bac7d80e-5544-4ea5-ae12-478281338389持续时间:612.63毫秒计费持续时间:700毫秒内存大小:128 MB最大使用内存:97 MB初始持续时间:557.69毫秒

在这些情况下,一个常见的问题是权限错误。要允许AWS Lambda在S3中放置对象,需要在Lambda执行角色中设置此类权限

下面是一个允许Lambda在S3中执行任何操作的策略示例:

{
    "Version": "2012-10-17",
    "Statement": [
{
            "Effect": "Allow",
            "Action": [
                "s3:ListAllMyBuckets",
                "s3:GetBucketLocation"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::ExampleBucketName",
                "arn:aws:s3:::ExampleBucketName/*"
            ]
        }
    ]
}

出于安全目的,将操作限制为您实际需要的操作非常重要,例如PutObject,您可以获得更多信息。

下面是一个如何将文件从HTTP URL流式传输到S3的示例。它使用Promissions/async/await而不是回调,并且它省去了Jimp包(对此我知之甚少),而使用了更传统的
fetch
API:

注意:如果在上传到S3时没有明确提供内容类型,则它将被设置为
application/octet stream
,这在客户端下载对象时会出现问题。因此,该代码首先确定文件的内容类型,并在流式传输到S3时进行设置

const AWS = require('aws-sdk');
const fetch = require('node-fetch');
const stream = require('stream');
const s3 = new AWS.S3();

const uploadStream = ({ Bucket, Key, ContentType }) => {
  const pass = new stream.PassThrough();
  return {
    writeStream: pass,
    promise: s3.upload({ Bucket, Key, ContentType, Body: pass }).promise(),
  };
}

const uploadFetch = async ({ url, Bucket, Key, ContentType }) => {
  const response = await fetch(url);
  const { writeStream, promise } = uploadStream({Bucket, Key, ContentType});
  response.body.pipe(writeStream);
  return promise;
}

exports.handler = async (_event, _context) => {
  const source_jpeg = {
    Key: 'audi.jpeg',
    Bucket: 'mybucket',
    url: 'https://upload.wikimedia.org/wikipedia/commons/0/08/Audi_A3_2015.jpeg',
  };

  // HEAD the source image to get content type
  const rc_head = await fetch(source_jpeg.url, {method: 'HEAD'});
  const content_type = rc_head.headers.get('content-type');
  console.log('head:', rc_head.status, rc_head.statusText, content_type);

  try {
    // GET the source image and stream it to S3
    const parms = {...source_jpeg, ContentType: content_type};
    const rc_upload = await uploadFetch(parms);
    console.log('get/upload jpeg:', rc_upload);
  } catch(e) {
    console.log(e);
  }
};

另外,请确保Lambda函数配置了合理的超时(默认超时为3秒)。

如果这有助于其他人,请将需要写入缓冲区的映像。下面的行修复了它:

const buffer = await image.getBufferAsync(imageType);
然后将buffer用于S3 Body参数。因此,完整的脚本是:


    "use strict";

    const AWS = require("aws-sdk");
    const Jimp = require("jimp");
    const s3 = new AWS.S3();
    const imageType = "image/jpeg";
    const bucket = 'bucketxzy';

    exports.handler = async (event, context) => {
        let objectKey = 'sampleimage.jpeg';
        const image = await Jimp.read('https://www.sampleurl.com/sampleimage.jpg/');
        const buffer = await image.getBufferAsync(imageType);

        return s3.putObject({
            Bucket: bucket,
            Key: objectKey,
            Body: buffer,
            ContentType: imageType
        }).promise();


    };


您是否在处理异常的位置有任何内容。?如果什么都没有,那么可能是对你隐藏了真正的例外
console.log(err)
应该会有帮助。如果您还可以在CloudWatch中共享Lambda的输出以进行调试,那就太好了。这是一个很好的日志记录功能。这记录了我在上面添加的MIME和缓冲区问题。搜索这个会导致几个从未解决的git线程。在这一点上,我非常感谢关于不同脚本的建议,以下载并将img保存到S3。感谢您的建议,但这确实具有必要的权限。我正在使用另一个函数中的相同角色,该函数写入S3。感谢您的建议,但这会返回与我在上面发布的“errorMessage找不到缓冲区的MIME”相同的错误消息,@RyanK此代码适用于常规JPEG,例如我在代码中使用的JPEG。它不会产生“找不到缓冲区的MIME”。该错误消息来自Jimp包,我在回答中没有使用该包,因此我假设您一定修改了我的回答,引入了Jimp,并重新引入了相同的错误。这种方法的缺点是您将整个图像下载到内存中,而不是流式传输图像。正确编写的流媒体解决方案没有理由不起作用。