【问题标题】:Image uploaded to S3 becomes corrupted上传到 S3 的图像已损坏
【发布时间】:2021-03-15 13:50:29
【问题描述】:

我在将文件从邮递员上传到 aws lambda + s3 时遇到问题。如果我理解正确,图像必须是 base64 字符串并通过 JSON 发送以使用 lambda 和 API Gateway,因此我将图像转换为 base64,并在邮递员中使用 base64 字符串

文件上传到 S3,但是当我下载 s3 对象并打开它时,我得到了

所以我认为我上传的不正确。我使用了 base64 到图像转换器并且图像出现了,所以 base64 字符串在通过邮递员发送之前是正确的,所以我的设置中的某些东西是关闭的。我究竟做错了什么?感谢您的帮助!

上传.js

const AWS = require('aws-sdk');
const s3 = new AWS.S3();
exports.handler = async (event, context, callback) => {
    let data = JSON.parse(event.body);
    let file = data.base64String;


    const s3Bucket = "upload-test3000";
    const objectName = "helloworld.jpg";
    const objectData = data.base64String;
    const objectType = "image/jpg";
    try {
        const params = {
            Bucket: s3Bucket,
            Key: objectName,
            Body: objectData,
            ContentType: objectType
        };
        const result = await s3.putObject(params).promise();
        return sendRes(200, `File uploaded successfully at https:/` + s3Bucket + `.s3.amazonaws.com/` + objectName);

    } catch (error) {
        return sendRes(404, error);
    }
};
const sendRes = (status, body) => {
    var response = {
        statusCode: status,
        headers: {
            "Content-Type": "application/json",
            "Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token",
            "Access-Control-Allow-Methods": "OPTIONS,POST,PUT",
            "Access-Control-Allow-Credentials": true,
            "Access-Control-Allow-Origin": "*",
            "X-Requested-With": "*"
        },
        body: body
    };
    return response;
};

.png

【问题讨论】:

  • 你能在 gist 或 pastebin 中发布 base64 编码的字符串吗?所以我们可以仔细检查它是否有效。
  • 这是我使用的base64字符串pastebin.com/b2A55Lh3
  • 不幸的是,它说粘贴不再可用:(
  • 是的,pastebin 正在删除它。这是一个不同的来源:0bin.net/paste/z0zslIdN#E9XxfpS-KlQaVRmPbLx2ZIz2nQH/…
  • 在调用 s3.putObject 之前将您的 base64 字符串解码回 jpeg。然后写入 S3 的对象将是一个有效的二进制 jpg 文件,而不是包含 jpg 的 base64 字符串。如果你从 s3 下载 helloworld.jpg 我假设它的 base64 文本不是二进制的?

标签: node.js amazon-web-services amazon-s3 aws-lambda aws-api-gateway


【解决方案1】:

在构建参数时你应该添加内容编码,否则你只是上传文本数据:

const params = {
  Bucket: s3Bucket,
  Key: objectName,
  Body: objectData,
  ContentType: objectType,
  ContentEncoding: 'base64'
};

编辑

好的,我已经检查了文件,我想你可能误解了将图像存储在 base64 中会发生什么。

Windows 或浏览器无法读取 base64 格式的 jpg 文件(据我所知),必须先对其进行转换。当您在浏览器中有一个带有 base64 源的图像时,浏览器会即时处理此转换,但“helloworld.jpg”容器中的 base64 数据在 Windows 中如果不进行转换就毫无用处。

有两个选项,要么在图像到达您的服务器后进行转换,然后直接以 utf8 格式上传,或者在两者之间添加一层,根据请求转换图像。

【讨论】:

  • 我在参数中添加了ContentEncoding: 'base64',但我遇到了同样的问题。我下载了对象,但在尝试打开 jpg 时出现不支持的格式错误。有什么想法吗?
  • 如果您下载文件并在文本编辑器中打开,它是否只显示您上传的相同 base64 字符串?
  • 是的,我使用了 diffchecker,它完全一样
  • 这是问题所在,编码似乎不适用于文件,因此您将 base64 数据存储在标准编码(可能是 utf8)中。如果您在 AWS 中检查文件的元数据,它是否显示 Content Encoding 值?
  • 这里是s3对象的元数据{'AcceptRanges': 'bytes', 'LastModified': '2020-12-03T15: 23: 14.000Z', 'ContentLength': 27496, 'ETag': '"56cd10223bb062f921628bc62d6d2c6a"', 'ContentEncoding': 'base64', 'ContentType': 'image/jpg', 'Metadata': {} }
【解决方案2】:

我通过像这样添加 JSON 格式的 base64 字符串来让它工作

然后发送

let decodedImage = Buffer.from(encodedImage, 'base64'); 作为Body 参数。

更新了 upload.js

const AWS = require('aws-sdk');
var s3 = new AWS.S3();


exports.handler = async (event) => {

    let encodedImage = JSON.parse(event.body).base64Data;
    let decodedImage = Buffer.from(encodedImage, 'base64');
    var filePath = "user-data/" + event.queryStringParameters.username + ".jpg"
    var params = {
        "Body": decodedImage,
        "Bucket": process.env.UploadBucket,
        "Key": filePath
    };

    try {
        let uploadOutput = await s3.upload(params).promise();
        let response = {
            "statusCode": 200,
            "body": JSON.stringify(uploadOutput),
            "isBase64Encoded": false
        };
        return response;
    }
    catch (err) {
        let response = {
            "statusCode": 500,
            "body": JSON.stringify(eerr),
            "isBase64Encoded": false
        };
        return response;
    }

};

我发现这个article 非常有帮助

【讨论】:

    【解决方案3】:

    问题可能是Body中图像的传递格式,因为它没有按s3.upload参数的预期传递(它说Body key必须是Buffer才能传递)。

    所以,简单的解决方案是将 Body 作为缓冲区传递,如果您的文件 存在于目录中的任何位置,则不要传递它

    // Wrong Way 
    
    const params = {
       Bucket: 'Your-Buket-Name',
       Key: 'abc.png', // destFileName i.e the name of file to be saved in s3 bucket
       Body: 'Path-To-File'
    }
    

    现在,问题是文件以原始文本形式上传,格式已损坏,下载时操作系统无法读取。

    所以,要让它正常工作,就像通过它一样

    // Correct Way According to aws-sdk library
    
    const fs = require('fs'); 
    const imageData = fs.readFileSync('Path-To-File'); // returns buffer
    const params = {
       Bucket: 'Your-Buket-Name',
       Key: 'abc.png', // destFileName i.e the name of file to be saved in s3 bucket
       Body: imageData // image buffer
    }
    const uploadedFile = await s3.upload(params).promise();
    

    注意:在回答过程中我使用的是 -> "aws-sdk": "^2.1025.0"

    希望这会对您或其他人有所帮助。谢谢!

    【讨论】:

      猜你喜欢
      • 2015-11-14
      • 2016-04-14
      • 2022-08-17
      • 1970-01-01
      • 2020-04-15
      • 2022-08-13
      • 1970-01-01
      • 2018-01-16
      相关资源
      最近更新 更多