1

I am using React, API gateway, and Lambda (Python) to obtain a pre-signed url to upload a file to an s3 bucket. But the files uploaded to the s3 bucket are always empty (0 bytes). And for some reason, when I upload a CSV in my React App. The uploaded file in s3 turns into an .XLS file but still named the original csv.

Here is my code:

<div>
    <input type="file" name="fileOne" onChange={fileUploadOne} />
</div>

...

const fileUploadOne = (event) => {
    const { files } = event.target;
    getPresignedUrl(files[0]).then((response) => {
      putToS3(files[0], response);
    });
  };

...

export async function getPresignedUrl(fileObject) {
  const requestOptions = {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
  };
  const response = await fetch(
    "https://<api_gateway_url>.amazonaws.com/<api_name>?filename=" +
      fileObject.name +
      "&filetype=" +
      fileObject.type,
    requestOptions
  );
  return await response.json();
}

export async function putToS3(fileObject, presignedUrl) {
  const requestOptions = {
    method: "PUT",
    headers: {
      "Content-Type": fileObject.type,
    },
    data: fileObject,
  };
  const response = await fetch(presignedUrl, requestOptions);
  return await response;
}

My Lambda code (which is accessed with getPresignedUrl function):

import json
import boto3
from botocore.exceptions import ClientError

def lambda_handler(event, context):
    params = event["queryStringParameters"]
    key = params.get('filename')
    filetype = params.get('filetype')
    
    s3_client = boto3.client('s3')
    client_action = 'put_object'
    bucket_name = '<bucket_name>'
    resp = generate_presigned_url(
        s3_client, client_action, {'Bucket': bucket_name, 'Key': key,'ContentType':filetype}, 1000)
    return {
        'statusCode': 200,
        'headers': {
            "Access-Control-Allow-Origin" : "*", # Required for CORS support to work
        },
        'body': json.dumps(resp)
    }

def generate_presigned_url(s3_client, client_method, method_parameters, expires_in):
    """
    Generate a presigned Amazon S3 URL that can be used to perform an action.

    :param s3_client: A Boto3 Amazon S3 client.
    :param client_method: The name of the client method that the URL performs.
    :param method_parameters: The parameters of the specified client method.
    :param expires_in: The number of seconds the presigned URL is valid for.
    :return: The presigned URL.
    """
    try:
        url = s3_client.generate_presigned_url(
            ClientMethod=client_method,
            Params=method_parameters,
            ExpiresIn=expires_in
        )
        print("Got presigned URL: %s", url)
    except ClientError:
        print(
            "Couldn't get a presigned URL for client method '%s'.", client_method)
        raise
    return url
2
  • What is the value of response in getPresignedUrl? AFAIK, the method returns the URL as a string - so the response.json() should not be necessary Commented Jul 1, 2021 at 7:57
  • @BertBlommers yup, it's a string. And yes .json() isnt necessary. Commented Jul 1, 2021 at 23:01

1 Answer 1

1

I figured out my mistake. My HTTP PUT request should have the fileObject in body not data.

export async function putToS3(fileObject, presignedUrl) {
  const requestOptions = {
    method: "PUT",
    headers: {
      "Content-Type": fileObject.type,
    },
    body: fileObject,
  };
  const response = await fetch(presignedUrl, requestOptions);
  return await response;
}

It was really very simple and a stupid mistake. Took me hours to figure it out.

Sign up to request clarification or add additional context in comments.

1 Comment

Still not working .<Message>Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter, Signature query string parameter or the Authorization header should be specified</Message>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.