【问题标题】:Upload to S3 from React Native with AWS Amplify使用 AWS Amplify 从 React Native 上传到 S3
【发布时间】:2020-03-26 08:29:08
【问题描述】:

我正在尝试使用 Amplify 从 React Native 将图像上传到 S3。我能够成功上传文本文件。但不是图像。

这是我的代码:

import React from 'react';
import {View, Text, Button, Image} from 'react-native';
import {identityPoolId, region, bucket} from '../auth';
import image from '../assets/background.png';
import Amplify, {Storage} from 'aws-amplify';

Amplify.configure({
    Auth: {identityPoolId,region},
    Storage : {bucket,region}
})

const upload = () => {
    Storage.put('logo.jpg', image, {contentType: 'image/jpeg'})
        .then(result => console.log('result from successful upload: ', result))
        .catch(err => console.log('error uploading to s3:', err));
}

const get = () => {   //this works for both putting and getting a text file
    Storage.get('amir.txt')
        .then(res => console.log('result get', res))
        .catch(err => console.log('err getting', err))
}

export default function ImageUpload(props) {

    return (
        <View style={{alignItems : 'center'}}>
            <Image style={{width: 100, height: 100}} source={image} />
            <Text>Click button to upload above image to S3</Text>
            <Button title="Upload to S3" onPress={upload}/>
            <Button title="Get from S3" onPress={get}/>
        </View>
    )

}

错误信息是:

error uploading to s3: [Error: Unsupported body payload number]

【问题讨论】:

    标签: image amazon-web-services react-native amazon-s3 aws-amplify


    【解决方案1】:

    在我们最近来自 React 的单页应用程序 (SPA) 风格的 Web 应用程序中,我们使用“S3 签名 URL”来高效上传/下载文件,我觉得与直接上传/下载相比,这带来了更简洁的设计.

    后端服务实现在什么地方?

    【讨论】:

    • 是的,我的移动应用程序也是如此。上传和下载速度更快,代码更干净。但这对他一点帮助都没有。
    • 我们想直接从前端上传到 S3。然后将对象的URL发回我们的后端,实现在node/express
    【解决方案2】:

    您可以在您的节点服务器上执行此操作,将其保存为 URL 并将其发送回应用程序。 它看起来像:

    const AWS = require('aws-sdk');
    var s3 = new AWS.S3({accessKeyId:'XXXXXXXXXXXX', secretAccessKey:'YYYYYYYYYYYY', region:'REGION'});
    
    var params = {Bucket: 'yourBucket', Key: 'your_image/your_image.jpg', ContentType: 'image/jpeg'};
    s3.getSignedUrl('putObject', params, function (err, url) {
        // send it back to the app
    });
    

    在应用程序方面,您将拥有类似的内容:

    const xhr = new XMLHttpRequest()
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          Alert.aler("Upload", "Done");
        } else {
         Alert.aler("Upload", "Failed");
        }
      }
    }
    xhr.open('PUT', presignedUrlReceiveFromServer)
    xhr.setRequestHeader('Content-Type', fileType)
    xhr.send({ uri: imageFilePath, type: fileType, name: imageFileName })
    

    希望对你有帮助

    【讨论】:

    • 谢谢。这很好,但我想保持简单并直接从前端进行。我只是不明白为什么我可以使用我的方法上传文本文件,而不是图像文件。这可能是我想念的小东西。
    【解决方案3】:

    我最终使用 react-native-aws3 库将图像上传到 S3。 我希望可以更直接地找到有关如何使用 AWS amplify 直接上传图像的答案,但它不起作用。所以这就是我所做的:

    (此函数的包装器是一个 React 组件。我正在使用来自“expo-image-picker”的 ImagePicker、来自“expo-permissions”的权限和来自“expo-constants”的常量来设置从相机胶卷)

    import {identityPoolId, region, bucket, accessKey, secretKey} from '../auth';
    import { RNS3 } from 'react-native-aws3';
    
    
    
    async function s3Upload(uri) {
    
          const file = {
                   uri,
                   name : uri.match(/.{12}.jpg/)[0],
                   type : "image/png"
          };
    
            const options = { keyPrefix: "public/", bucket, region, 
            accessKey, secretKey, successActionStatus: 201}
    
            RNS3.put(file, options)
                .progress(event => {
                    console.log(`percentage uploaded: ${event.percent}`);
                })
                .then(res => {
                    if (res.status === 201) {
                        console.log('response from successful upload to s3:', 
                        res.body);
                        console.log('S3 URL', res.body.postResponse.location);
                        setPic(res.body.postResponse.location);
    
                    } else {
                        console.log('error status code: ', res.status);
                    }
                })
                .catch(err => {
                    console.log('error uploading to s3', err)
                })
    }
    
    const pickImage = async () => {
            let result = await ImagePicker.launchImageLibraryAsync({
                mediaTypes : ImagePicker.MediaTypeOptions.All,
                allowsEditing : true,
                aspect : [4,3],
                quality : 1
            });
    
            console.log('image picker result', result);
    
            if (!result.cancelled) {
                setImage(result.uri);
                s3Upload(result.uri);
            }
        }
    
    

    【讨论】:

    • 您的密钥在此处公开 - 您是如何解决必须向应用程序本身添加密钥这一明显的安全问题的?
    • 我没有看到这里暴露的密钥。密钥位于本地 .env 文件中,而不是此处。除非我不小心错过了
    • 它是如何从env 到你上面使用的options 哈希的?我的意思是“暴露”,因为您必须将凭据添加到您加载到人们手机上的实际代码中。您需要该密钥可读且以纯文本形式将其添加到此处:const options = ...etc 为了避免将密钥添加到您的存储库或落在人们手机上的代码,您需要类似 s3 预签名 url 之类的东西战略。即看看:devcenter.heroku.com/articles/s3-upload-node ... 作为一个基本示例。除非我在这里完全遗漏了一些东西。
    • 您好,我也是这样做的,但我收到了这个错误 {"headers": {}, "status": 0, "text": "Stream Closed"} 任何帮助都将得到批准跨度>
    • @user1230795。你说的完全有道理。我可能需要使用预签名的 url 策略。将来会做。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2020-08-21
    • 2020-11-08
    • 1970-01-01
    • 2022-09-28
    • 2017-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多