'Using fetch api for uploading image using presigned url amazon s3

Hi I am trying customer upload their picture to amazon s3 directly in reactjs web app. I am generating presigned url in the backend like this

def get_presigned_url(file_extension, content_type, user_id) do
  config = get_aws_s3_config()
  bucket = get_bucket_name()
  filename = create_s3_file_name(file_extension, user_id)
  query_params = [{"ContentType", content_type}]

  ExAws.S3.presigned_url(config, :put, bucket, filename, query_params: query_params)
end

and generated url looks like this.

https://s3.us-west-1.amazonaws.com/churchapp-la/5/ab49d601efed40e0a6de0509ab78c091.png?ContentType=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=credentials%2Fus-west-1%2Fs3%2Faws4_request&X-Amz-Date=20200422T230320Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=68e0915ba1abb2722107c96b684e3a62f2e67aae9594bd4dece45132853f5be2"

in client I am doing like this

async function uploadImage(url, data, headers) {
    const response = await fetch(url, {
      method: "PUT",
      headers: headers,
      body: data
    });
    return response;
  }

const handleUpload = e => {
    const formData = new FormData();
    formData.append("image", file);

    const myHeaders = new Headers();
    myHeaders.append("ContentType", file.type);
    uploadImage(presignedUrl, formData, myHeaders)
      .then(data => console.log("Printing uploadImage result: ", data.url))
      .catch(error => {
        console.log("Error: ", error);
      });
  };

When I click upload, handleUpload function is invoked and uploaded to S3. But When I tried to open a file, It didn't open. And says signature does not match.

I googled it. some says Header should match in backend and also in frontend which I think I did correctly.

I set only ContentType and value is same in both side..

Any ideas? Please help!



Solution 1:[1]

You should set Content-Type and not ContentType as a header name at both places.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type

Solution 2:[2]

Expounding on @szaboat's answer, instead of

const myHeaders = new Headers()

try:

const myHeaders = { 'Content-Type': 'multipart/form-data' }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 szaboat
Solution 2 Julian