如何允许对 AWS S3 存储桶发出 POST 请求?

Max*_*ies 5 javascript amazon-s3 node.js reactjs

问题

我正在尝试使用预先签名的发布请求将文件上传到 S3 存储桶(大致遵循此博客文章)。我的服务器(节点)使用 生成预签名的 post 请求createPresignedPost,然后将其返回给客户端(React),客户端使用它将用户生成的文件上传到我们的 S3 存储桶。

目前,POST客户端向存储桶发出的任何请求都会失败,并显示405 Method Not Allowed。我检查了响应标头,发现Allow标头没有列出POST,尽管Access-Control-Allow-Methods确实列出了。

我还需要执行其他操作才能允许对存储桶进行 POST 请求吗?

(注意 - 我尝试使用预签名POST请求而不是常规预签名网址(使用PUT)的原因是因为我需要指定文件类型和大小的限制,后者似乎不支持)

上下文/其他信息

S3 存储桶没有策略。它确实有一个 CORS 政策,即

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "POST",
            "PUT",
            "HEAD",
            "DELETE"
        ],
        "AllowedOrigins": [
            "http://localhost:3000",
            "http://localhost:8000",
            ...
        ],
        "ExposeHeaders": [
            "ETag",
            "x-amz-meta-custom-header"
        ]
    }
]
Run Code Online (Sandbox Code Playgroud)

用于生成预签名 POST 请求的服务器端代码:

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "POST",
            "PUT",
            "HEAD",
            "DELETE"
        ],
        "AllowedOrigins": [
            "http://localhost:3000",
            "http://localhost:8000",
            ...
        ],
        "ExposeHeaders": [
            "ETag",
            "x-amz-meta-custom-header"
        ]
    }
]
Run Code Online (Sandbox Code Playgroud)

以及使用此预签名请求上传文件的客户端代码:

const signS3PostRequest = async ({ fileName, fileType, prefix, bucket }) => {
  const params = {
    Bucket: bucket,
    Fields: {
      $key,
    },
    Expires: 60,
    ContentType: fileType,
    ACL: 'private',
    Conditions: [['content-length-range', 0, 10000000]],
  }

  const s3 = new aws.S3({
    apiVersion: 'latest',
    region: $region,
    accessKeyId: process.env.AWS_ACCESSKEYID,
    secretAccessKey: process.env.AWS_SECRETACCESSKEY,
  })

  return new Promise((resolve, reject) => {
    s3.createPresignedPost(params, (err, data) => {
      if (err) {
        ...
      } else {
        resolve(data)
      }
    })
  })
}
Run Code Online (Sandbox Code Playgroud)

编辑:我得到的回复s3.createPresignedPost如下所示:

{
    "url": "https://s3.amazonaws.com/$BUCKET_NAME",
    "fields": {
        "key": "test/6zb3rewm8cjydpslti3g/test.jpeg",
        "bucket": "$BUCKET_NAME",
        "X-Amz-Algorithm": "AWS4-HMAC-SHA256",
        "X-Amz-Credential": "$CREDENTIAL",
        "X-Amz-Date": "20221230T090441Z",
        "Policy": "eyJleHBpcmF0aW9uIjoiMjAyMi0xMi0zMFQwOTowNTo0MVoiLCJjb25kaXRpb25zIjp...",
        "X-Amz-Signature": "$SIGNATURE"
    }
}
Run Code Online (Sandbox Code Playgroud)

当尝试使用签名的发布请求上传文件时,S3 的响应如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>MethodNotAllowed</Code>
    <Message>The specified method is not allowed against this resource.</Message>
    <Method>POST</Method>
    <ResourceType>OBJECT</ResourceType>
    <RequestId>HTYWNACA6A1J6BBS</RequestId>
 <HostId>BSV4mFijEfgZEiMu6nVxqP9aocuhAwN7et/UfrO4r1PmkeFZ8nVUsNmcLVZoWCe06zrEFJXDfsE=</HostId>
</Error>
Run Code Online (Sandbox Code Playgroud)