无法通过从我的节点后端创建的预签名 URL 将 PDF 上传到 S3 存储桶

问题描述 投票:0回答:1

场景:

  1. 客户端(Nextjs 客户端组件)查询后端(NextJS Rest 端点)以获取预签名 URL
  2. 后端通过
    getSignedUrl
  3. 获取 S3 的预签名 URL
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { env } from "@/env";

const AWS_REGION = "ap-southeast-2";

const s3Client = new S3Client({
  region: AWS_REGION,
  credentials: {
    accessKeyId: env.AWS_S3_ACCESS_ID,
    secretAccessKey: env.AWS_S3_ACCESS_KEY,
  },
});

const command = new PutObjectCommand({
     Bucket: s3Object.bucket,
     Key: s3Object.key,
     // I also tried passing the contenttype here to see if it changed anything. But no it didn't.
     // ContentType: s3Object.contentType,
     // Might need more fields here to refine...
});

// Calculate dynamic expiration time based on file size, user's internet connection speed, etc.
const expiresIn = calculateExpirationTime(s3Object);

const presignedUrl = await getSignedUrl(s3Client, command, { expiresIn });

return presignedUrl;
  1. 客户端从后端接收预签名 URL
  2. 客户端将文件块发送到预先签名的 URL
// Uploads a chunk to the presigned URL
const uploadPart = (opts: {
  url: string;
  chunk: Blob;
  contentType: string;
  chunkSize: number;
  fileName: string;
  maxRetries: number;
}) =>
  fetch(opts.url, {
    method: "PUT",
    body: opts.chunk,
    //headers: {
    //  "Content-Type": opts.contentType,
    //},
  })
  1. 前端抛出 COR 错误:
Access to fetch at 'https://mybucket.s3.ap-southeast-2.amazonaws.com/mydoc.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AMZ_VALUE%2Fap-southeast-2%2Fs3%2Faws4_request&X-Amz-Date=20240516T010037Z&X-Amz-Expires=14400&X-Amz-Signature=SIGNATURE&X-Amz-SignedHeaders=host&x-id=PutObject' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

OPTIONS 请求已发送并返回为

403 Forbidden

Request Method:
OPTIONS
Status Code:
403 Forbidden
Remote Address:
<IP>:443
Referrer Policy:
strict-origin-when-cross-origin

响应标头:

Content-Type:
application/xml
Date:
Thu, 16 May 2024 01:03:33 GMT
Server:
AmazonS3
Transfer-Encoding:
chunked
X-Amz-Id-2:
<ID>
X-Amz-Request-Id:
<ID>

请求标头:

Accept:
*/*
Accept-Encoding:
gzip, deflate, br, zstd
Accept-Language:
en-US,en;q=0.9
Access-Control-Request-Method:
PUT
Cache-Control:
no-cache
Connection:
keep-alive
Host:
mybucket.s3.ap-southeast-2.amazonaws.com
Origin:
http://localhost:3000
Pragma:
no-cache
Referer:
http://localhost:3000/
Sec-Fetch-Dest:
empty
Sec-Fetch-Mode:
cors
Sec-Fetch-Site:
cross-site
User-Agent:
<AGENT>

S3 存储桶权限

我已经正确配置了。我尝试了许多不同的变体,包括在AllowedOrigins中显式定义localhost:3000。

CORS 设置:

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "PUT",
            "POST",
            "DELETE",
            "HEAD"
        ],
        "AllowedOrigins": [
            "*"
        ]
    }
]

附加到用户的策略

生成预签名 URL 的用户附加了以下策略:

  {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Action": [
          "s3:GetObject",
          "s3:GetObjectVersion",
          "s3:PutObject"
        ],
        "Resource": [
          "arn:aws:s3:::mybucket",
          "arn:aws:s3:::bmybucket/*"
        ],
        "Effect": "Allow"
      }
    ]
  }

我已经在这个问题上挣扎了一段时间,并尝试了来自 SO 和 Google 的许多建议。没有一个有效。我有一种感觉,我错过了一些小细节,这让我感到悲伤。

更新1

当我在 Postman 中测试 PUT 命令时,出现以下错误,该错误与 COR 错误不同:

<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>PermanentRedirect</Code>
    <Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message>
    <Endpoint>s3.amazonaws.com</Endpoint>
    <Bucket>mybucket</Bucket>
    <RequestId>__ID__</RequestId>
    <HostId>__ID__</HostId>
</Error>
javascript amazon-web-services amazon-s3 cors cross-browser
1个回答
0
投票

事实证明我已经按照书本做了所有事情,这归结为疏忽使用了错误的存储桶名称。

我的 CDK 部署创建了具有唯一名称的存储桶,并且我使用的是我设置的名称。但是,我完全忽略了 AWS 控制台中存储桶的名称。

© www.soinside.com 2019 - 2024. All rights reserved.