将图像上传到AWS S3

时间:2020-09-25 09:34:45

标签: react-native amazon-s3

我是React Native的初学者。我的问题是,我正在尝试将图像从相机发送到AWS S3。这是我的最新代码。

import React from 'react';

import { StyleSheet, Text, View, TouchableOpacity, Button, Image  } from 'react-native';
import ImagePicker from 'react-native-image-picker';
import { RNS3 } from 'react-native-aws3';
import fs from 'react-native-fs';
import Buffer from 'buffer';
import AWS from 'aws-sdk';



 function uploadToS3(image){
  const filename = "the_file.jpeg";
  const options = {
    keyPrefix: "uploads/",
    bucket: "this is bucketname",
    region: "this is region",
    accessKey: "this is access key",
    secretKey: "this is secret key",
    successActionStatus: 201
  }

 
  try{
    const s3 = new AWS.S3({accessKeyId: options.accessKey, secretAccessKey:options.secretKey, region:options.region});
    var UploadURL;
    const params = {Bucket: options.bucket, Key: options.keyPrefix+filename, ContentType: image.type};
    
    s3.getSignedUrl('putObject', params, function (err, url) {
        console.log('Your generated pre-signed URL is', url);
        UploadURL = url;
        
        
        const xhr = new XMLHttpRequest()
        xhr.onreadystatechange = function() {
          if (xhr.readyState === 4) {
            if (xhr.status === 200) {
              console.log("ok: ", xhr.response);
              alert("success");
            } else {
              console.log("no: " , xhr.response);
              alert("no");
            }
          }
        }
      
        xhr.open('PUT', UploadURL)

        xhr.setRequestHeader('Content-Type', image.type)
        xhr.send({image})
            
   
    });
  
    
  } catch(error){
    console.log("err : ",error)
  }
}



class HomeScreen extends React.Component {
  constructor(props) {
    global.currentScreenIndex = 'HomeScreen';
    super(props);
    this.state = {
      resourcePath: {},
      requestStatus: {},
      employees: {},
      response: {},
    };
  }

  cameraLaunch = (id) => {
    console.log(id);
    let options = {
      title: 'Select Picture',
      storageOptions: {
          skipBackup: true,
          path: 'images',
  
      },
      base64: true,
      maxWidth: 400,
      maxHeight: 400
    };
    
    ImagePicker.launchCamera(options, (res) => {
      //console.log('Response = ', res);
  
      if (res.didCancel) {
        console.log('User cancelled image picker');
      } else if (res.error) {
        console.log('ImagePicker Error: ', res.error);
      } else if (res.customButton) {
        console.log('User tapped custom button: ', res.customButton);
        alert(res.customButton);
      } else {
        
        let source = res;
        this.setState({
          resourcePath: source,
        });
        
        uploadToS3(res);
      }
    });
  }
  

  render(){
    return (

      <View style={{ flex: 1, alignItems: 'center', marginTop: 100 }}>

      
      <Button
        onPress={()=>this.cameraLaunch(1)}
        title="OpenCamera"
        color="#841584"
      />
      <Text style={{ alignItems: 'center' }}>
                  {this.state.resourcePath.uri}
                </Text>

        <Image source={this.state.resourcePath} />
          </View>
    );
  }
};
export default HomeScreen;

相机或预签名的URL生成没有问题。如果运行,则“这是存储桶名称” /uploads/the_file.jpeg中将有the_file.jpeg,但问题是它的大小为0字节。我曾尝试仅发送image.data,但显然它只是使the_file.jpeg成为带有“ jpeg”扩展名的“ txt文件”。请帮忙。

ps:我知道此代码有多不安全。

2 个答案:

答案 0 :(得分:1)

您似乎错过了预签名URL的目的,即不需要AWS凭证即可上传对象。在您的示例中,您正在使用AWS凭证初始化S3客户端,在这种情况下,您只需使用s3.upload函数即可上传文件。

答案 1 :(得分:1)

我遇到了同样的问题,但没有任何帮助。这就是我所做的。

请确保按照放大指南设置应用。放大初始化,放大添加身份验证,放大推送,然后放大添加存储,然后执行此操作。

import Amplify, { Storage } from 'aws-amplify'
import config from './src/aws-exports'
// import awsconfig from './aws-exports';
// Might need to switch line 7 to awsconfig 
Amplify.configure(config)

import { StatusBar } from 'expo-status-bar';
import React, { useState, useEffect } from 'react';
import { Button, Image, View, Platform, StyleSheet, Text, TextInput } from 'react-native';
import * as ImagePicker from 'expo-image-picker';

function App() {
  const [image, setImage] = useState(null)
  const [name, setName] = useState('Evan Erickson')

  useEffect(() => {
    (async () => {
      if (Platform.OS !== 'web') {
        const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
        if (status !== 'granted') {
          alert('Sorry, we need camera roll permissions to make this work!');
        }
      }
    })();
  }, []);

  const pickImage = async () => {
    let result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsEditing: true,
      aspect: [4, 3],
      quality: 1,
    });
    
    console.log(result) 

    async function pathToImageFile(data) {
      try {
        const response = await fetch(data);
        const blob = await response.blob();
        await Storage.put(`customers/${name}`, blob, {
          contentType: 'image/jpeg', // contentType is optional
        });
      } catch (err) {
        console.log('Error uploading file:', err);
      }
    }
    // later
    pathToImageFile(result.uri);
  }

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button title="Pick an image from camera roll" onPress={pickImage} />
      {image && <Image source={{ uri: image }} style={{ width: 200, height: 200 }} />}
      <Button title="Upload image" onPress={() => {alert(image)}} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

export default withAuthenticator(App)