将Base64字符串保存到Amazon S3

4
我正在开发一个基于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字符串发送到我的express服务器并发布数据:
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应用程序时,什么也没有发生。
例如,如果我在它被上传到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吗?
感谢您的帮助!

订阅,我也需要这个。 - Chris Geirman
3个回答

3

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

此答案解释了如何进行此转换。使用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
这是一个权限问题,与ReactNative或Base64编码无关。您遇到了一个“AccessDenied”错误,这意味着图像不是公开可用的。只有当您配置了正确的权限(甚至是特定文件,我将在下面解释),您才能收到图像的内容而无需签名URL。
要确定这是否是根本原因,您可以尝试在S3控制台中公开图像。只需转到您的S3存储桶并在图像文件上单击鼠标右键:
在上下文菜单中,有两个对您很有用的项目:“make public”和“open”。
如果您选择“open”,则会获得指向该文件的“signed url”,这意味着将纯url附加特定参数,以使此文件公开可用一段时间:
您还可以尝试“make public”,然后重新加载您的图像URL,看看它现在是否可用。
1. 方法,整个存储桶范围内: 一种解决方案是为整个存储桶创建IAM策略,以使其中的每个对象都变为公开。
{
  "Version": "2008-10-17",
  "Statement": [{
    "Sid": "AllowPublicRead",
    "Effect": "Allow",
    "Principal": {
      "AWS": "*"
    },
    "Action": [ "s3:GetObject" ],
    "Resource": [ "arn:aws:s3:::YOUR_BUCKET_NAME/*" ]
  }]
}

请前往AWS控制台中的存储桶,点击存储桶,在右侧窗格中打开"权限"。您可以创建一个类似上面的新策略。
第二种解决方案是针对特定对象的。
另一种方法是在putObject方法中添加ACL特定标头。请参考此链接:http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUTacl.html
'ACL'          => 'public-read'

我不知道您的后端SDK是什么,但我猜测它应该是类似这样的东西:
var data = {
    Key: test_img,
    Body: req.body.img,
    ContentEncoding: 'base64',
    ContentType: 'image/png',
    ACL: 'public-read',
  };

我在这里添加了ACL特定的行。 根据SDK的不同,可能需要使用纯aws头文件"x-amz-acl: public-read"而不是"ACL:public-read"。尝试两种方法。


很遗憾,这个解决方案对我没有起作用。我已经在我的存储桶的IAM策略中添加了内容,并尝试从它们各自的URL加载从相机胶卷保存的图像时,我只看到一个小的空白白色正方形出现在页面的左上角。我确保我的存储桶中的图像也是公共的,但我仍然遇到同样的问题。只有我从我的相机胶卷加载的以base64字符串为基础的图像无法正常工作,而我手动上传的一些测试图像则显示正常。 - Onaracs

0
将 Bucket 策略添加到您的存储桶中即可解决此问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接