【问题标题】:AWS S3 presigned url with React uploads empty file带有 React 的 AWS S3 预签名 URL 上传空文件
【发布时间】:2021-07-01 07:09:00
【问题描述】:

我正在使用 React、API 网关和 Lambda (Python) 来获取预签名的 url,以将文件上传到 s3 存储桶。但是上传到 s3 存储桶的文件总是空的(0 字节)。出于某种原因,当我在我的 React 应用程序中上传 CSV 时。 s3中上传的文件变成了.XLS文件,但仍然命名为原始的csv。

这是我的代码:

<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;
}

我的 Lambda 代码(通过 getPresignedUrl 函数访问):

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

【问题讨论】:

  • getPresignedUrl 中response 的值是多少? AFAIK,该方法将 URL 作为字符串返回 - 所以 response.json() 应该不是必需的
  • @BertBlommers 是的,它是一个字符串。是的.json() 不是必需的。

标签: reactjs amazon-web-services amazon-s3 boto3 http-put


【解决方案1】:

我发现了我的错误。我的 HTTP PUT 请求应该在 body 中包含 fileObject 而不是数据。

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;
}

这真的很简单,而且是个愚蠢的错误。我花了几个小时才弄明白。

【讨论】:

  • 仍然无法正常工作。只允许一种身份验证机制;仅应指定 X-Amz-Algorithm 查询参数、Signature 查询字符串参数或 Authorization 标头
猜你喜欢
  • 2018-10-20
  • 2020-10-23
  • 1970-01-01
  • 2019-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-08
相关资源
最近更新 更多