将 base64 字符串保存到 Amazon S3

Posted

技术标签:

【中文标题】将 base64 字符串保存到 Amazon S3【英文标题】:Saving base64 string to Amazon S3 【发布时间】:2016-08-24 14:04:39 【问题描述】:

我正在开发一个 React Native 应用程序,我试图从用户的相机胶卷中获取图像,将它们转换为 base64 字符串并将它们存储到 Amazon S3 以供以后使用。

在这篇博文之后,我可以获取用户的相机胶卷并将图像转换为 base64: react-native-creating-a-custom-module-to-upload-camera-roll-images

然后,我将 base64 字符串图像数据发送到一个简单的 Express 服务器,该服务器已设置为将数据发布到我的 Amazon S3 存储桶。

// Only getting first img in camera roll for testing purposes
CameraRoll.getPhotos(first: 1).then((data) => 

  for (let i = 0; i < data.edges.length; i++) 
    NativeModules.ReadImageData.readImage(data.edges[i].node.image.uri, (imageBase64) => 

      // Does the string have to be encoded?
      // const encodeBase64data = encodeURIComponent(imageBase64);

      const obj = 
        method: 'POST',
        headers: 
          'Accept': 'application/json',
          'Content-Type': 'application/json',
        ,
        body: JSON.stringify(
          'img': imageBase64
        )
      

      fetch('http://localhost:3000/saveImg', obj)
        .then((res) => 
          console.log(JSON.parse(res._bodyInit));
        )

    )
  

在这种情况下,我的 imageBase64 变量是一个相当大的字符串,如下所示:/9j/4AAQSkZJRgABAQAASABIAAD/4QBYRXhpZgAATU0AKgAAA...abX+Yub/API3zf8A7G2Z/wDqdiD/AExyf/kT5R/2Kst/9QqB0x6H6GuBbr1R6D2foz+ZT/gof/yep8bf934f/wDqC6PX96+Cn/JruFf+6z/6t8UfwP4wf8nM4n9Mq/8AVbRPjOv1I/OAoA//2Q== ... 还有几个字符。

我正在将此 base64 字符串发送到我的快递服务器并发布数据:

app.post('/saveImg', function(req, res) 

  // this will be moved once testing is complete
  var s3Bucket = new AWS.S3(  params: Bucket: '[my_bucket_name]'  );

  // Do I need to append this string to the image?
  var baseImg = 'data:image/png;base64,' + req.body.img;

  var data = 
    Key: test_img,
    Body: req.body.img,
    ContentEncoding: 'base64',
    ContentType: 'image/png'
  ;

  s3Bucket.putObject(data, function(err, data)
   if (err) 
     console.log(err);
     console.log('Error uploading data: ', data);
    else 
     res.send(data);
     console.log('successfully uploaded the image!');
   
 );
  // res.send(base64data)
);

我成功地将数据发送到 Amazon S3 并在存储桶中查看了我的图像文件,但是当我尝试访问链接以查看实际图像本身或将其拉入我的 React Native 应用程序时,我什么也得不到。

ie 如果我在 Amazon S3 中访问上面的 test_img 的 URL,我会得到:

https://s3.amazonaws.com/my_bucket_name/test_img
This XML file does not appear to have any style information associated with    it. The document tree is shown below.
<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message>
  <RequestId>BCE6E07705CF61B0</RequestId>
    <HostId>
aF2l+ucPPHRog1QaaXjEahZePF0A9ixKR0OTzlogWFHYXHUMUeOf2uP7D/wtn7hu3bLWG8ulKO0=

     </HostId>
</Error>

我已经手动将图像上传到同一个存储桶,它们的链接看起来很好,而且我还可以将它们拉到我的 React Native 应用程序中查看。

我的问题是在获取 base64 字符串数据并将其发送到我的 Express 服务器以保存到我的存储桶之间我做错了什么? 是否必须对 base64 字符串进行编码? 在将 base64 字符串发送到 Express 之前,是否需要将其转换为 Blob?

感谢您的帮助!

【问题讨论】:

订阅,我也需要这个 【参考方案1】:

我刚刚遇到了同样的问题。在上传到 S3 之前,您必须将 base64 字符串转换为 Blob。

This answer 解释了如何进行这种转换。使用node-fetch,以下是在您的示例中集成的方法:

require('node-fetch')

app.post('/saveImg', function(req, res) 

  // this will be moved once testing is complete
  var s3Bucket = new AWS.S3(  params: Bucket: '[my_bucket_name]'  );

  var imageUri = 'data:image/png;base64,' + req.body.img;

  fetch(imageUri)
    .then(function(res) return res.blob() )
    .then(function(image)
      var data = 
        Key: test_img,
        Body: image,
        ContentEncoding: 'base64',
        ContentType: 'image/png'
      ;

      s3Bucket.putObject(data, function(err, data)
       if (err) 
         console.log(err);
         console.log('Error uploading data: ', data);
        else 
         res.send(data);
         console.log('successfully uploaded the image!');
       
     );
   )
);

完成后,您可以在 S3 上预览上传的图片或将其拉入您的应用。

【讨论】:

【参考方案2】:

向您的存储桶添加存储桶策略将解决该问题。

【讨论】:

【参考方案3】:

这是一个权限问题,与 ReactNative 和 Base64 编码无关。

您遇到 “AccessDenied”-错误,这意味着该图像不公开。只有当您使用正确的权限(甚至是特定文件,我将在下面解释)配置您的存储桶时,您才会收到没有签名 URL 的图像内容。

要调查这是否是根本原因,您可以尝试在 s3 控制台中公开图像。只需转到your s3-bucket 并右键单击图像文件:

在上下文菜单中为您列出了两个有趣的项目:“公开”“公开”

如果您选择“打开”,您将获得文件的“签名 url”,这意味着图像的纯 url 将附加特定参数,以使该文件在一段时间内公开可用:

您也可以尝试“公开”并重新加载您的图片网址,看看它现在是否可供您使用。

1.方法,桶范围:

一种解决方案是为整个存储桶创建一个 IAM-Policy 以公开其中的每个对象:


  "Version": "2008-10-17",
  "Statement": [
    "Sid": "AllowPublicRead",
    "Effect": "Allow",
    "Principal": 
      "AWS": "*"
    ,
    "Action": [ "s3:GetObject" ],
    "Resource": [ "arn:aws:s3:::YOUR_BUCKET_NAME/*" ]
  ]

因此,在 AWS 控制台中转到您的存储桶,单击存储桶,然后在右侧窗格中打开“权限”。您可以创建与上述类似的新策略。

2。第二种解决方案,对象特定

另一种方法是将ACL-specific headers 添加到 putObject-Method:

'ACL'          => 'public-read'

我不知道你的后端 SDK,但我猜是这样的:

var data = 
    Key: test_img,
    Body: req.body.img,
    ContentEncoding: 'base64',
    ContentType: 'image/png',
    ACL: 'public-read',
  ;

我刚刚在此处添加了 ACL 特定行。 根据 SDK 的不同,可能需要使用普通的 aws-headers“x-amz-acl:public-read”而不是“ACL:public-read”。两个都试试。

【讨论】:

不幸的是,这个解决方案对我不起作用。我为我的存储桶添加了 IAM-Policy,当我尝试从它们各自的 url 加载从相机胶卷中保存的图像时,我只看到页面左上方出现一个小的空白白色方块。我确保我的存储桶中的图像也是公开的,但我仍然遇到同样的问题。只有我从相机胶卷作为 base64 字符串加载的图像不能正常工作,因为我在测试时手动上传的一些图像看起来很好。

以上是关于将 base64 字符串保存到 Amazon S3的主要内容,如果未能解决你的问题,请参考以下文章

Amazon S3 .NET:上传 base64 图像数据?

使用 Amazon s3 boto 库,如何获取已保存密钥的 URL?

尽管存储桶是公共的,但 Amazon S3 base64 图像不适用于 og:image 标签

如何仅使用 JavaScript 将 base64 编码的图像数据上传到 S3?

PHP 将远程图像保存到 Amazon S3

无法从 Amazon S3 下载具有特殊字符的文件