1

I am trying to get an presigned url image upload working correctly. Currently the upload succeeds when selecting an image from the IOS simulator, however when I actually try to view the file it seems the file is corrupted and will not open as an image. I suspect it has something to do with my FormData but not sure.

export async function receiptUpload(file) {

  const date = new Date();
  const headers = await getAWSHeaders();

  const presignUrl = await request.post(
      urls.fileUpload.presignUpload,
      {file_name: `${date.getTime()}.jpg`},
      {headers}
    )
    .then(res => res.data);

  const formData = new FormData();
  formData.append('file', {
    name: `${date.getTime()}.jpg`,
    uri: file.uri,
    type: file.type
  });

  const fileUpload = presignUrl.presignUrl && await request.put(
      presignUrl.presignUrl,
      formData
    )
    .then(res => res.status === 200);

}

I have tried from other fixes to change the file uri like so...

Platform.OS === 'android' ? file.uri : file.uri.replace('file://', '');

however this does not seem to work either.

Sandra Willford
  • 3,459
  • 11
  • 49
  • 96

3 Answers3

1

I did this just recently in my current project and the following code is a working example for my use case. I didn't need to convert to a blob either though I am uploading to AWS S3 so if you are uploading elsewhere that may be the issue.

export const uploadMedia = async (fileData, s3Data, setUploadProgress = () => {}) => {
    let sendData = { ...fileData };
    sendData.data.type = sendData.type;

    let formData = new FormData();

    formData.append('key', s3Data.s3Key);
    formData.append('Content-Type', fileData.type);
    formData.append('AWSAccessKeyId', s3Data.awsAccessKey);
    formData.append('acl', 'public-read');
    formData.append('policy', s3Data.s3Policy);
    formData.append('signature', s3Data.s3Signature);

    formData.append('file', sendData.data);

    return axios({
        method: 'POST',
        url: `https://${s3Data.s3Bucket}.s3.amazonaws.com/`,
        data: formData,
        onUploadProgress: progressEvent => {
            let percentCompleted = Math.floor((progressEvent.loaded * 100) / progressEvent.total)
            setUploadProgress(percentCompleted);
        }
    })
}

I would first check to see where the issue is occurring. After uploading can you view it on whatever storage service you are trying to upload it to. If so it's something on React Native side. If it doesn't ever get uploaded to the location you know its an error in your upload process. Might help you track the exact location of the error.

SKeney
  • 1,965
  • 2
  • 8
  • 30
0

I had to do this recently for a project. I believe the data is a base64 string when coming directly from the file input. So the issue is your are uploading a base64 string not the image by simply passing the data field. I had to process it before uploading to the signed URL with the following method.

private dataUriToBlob(dataUri) {
    const binary = atob(dataUri.split(',')[1]);
    const array = [];
    for (let i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
    }
    return new Blob([new Uint8Array(array)], { type: 'image/jpeg' });
}
Chase R Lewis
  • 2,119
  • 1
  • 22
  • 47
0

This answer fixed it for me: How can I upload image directly on Amazon S3 in React Native?

I had tried uploading with axios and fetch with FormData. The download went through but the image file was not readable, even when downloaded to my Mac from the S3 console:

The file "yourfile.jpg" could not be opened. It may be damaged or use a file format that Preview doesn’t recognize.

Only after trying to upload with XHR with the correct Content-Type header did it work. Your signedUrl should be correct as well, which seems to be the case if the download goes through.

luciancic
  • 16
  • 2