最近在重构博客系统,使用到了 cloudflare 家的 r2 作为图片和媒体资源的存储,使用 sws s3 sdk 构建 presigned url 上传的时候一直报 403 错误,找了半天,按照 cloudflare 家的文档和论坛上的方法实验均不行,
按照文档的代码
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"
import { getSignedUrl } from "@aws-sdk/s3-request-presigner"
const S3 = new S3Client({
endpoint: "https://4893d737c0b9e484dfc37ec392b5fa8a.r2.cloudflarestorage.com",
credentials: {
accessKeyId: "7dc27c125a22ad808cd01df8ec309d41",
secretAccessKey:
"1aa5c5b0c43defdb88f567487c071d17e234126133444770a706ae09336c57a4",
},
region: "auto",
})
const url = await getSignedUrl(
S3,
new PutObjectCommand({
Bucket: bucket,
Key: object,
}),
{
expiresIn: 60 * 60 * 24 * 7, // 7d
},
)
console.log(url)
后来发现还是报 cors 错误
"Access to fetch at '' 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."
后来看到需要设置 headers 才可以,也就是必须加入 allowedHeader,通过 put 方法上传文件的时候需要设置 content-type,不然上传后识别不到文件类型,才解决这个跨域的问题,只能说 cloudflare 家的文档也不太行,谷歌一搜好多人遇到这种问题,附上解决方案:
mkdir r2-cors && cd r2-cors
pnpm init
pnpm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
touch cors.jsimport { PutBucketCorsCommand, S3Client } from "@aws-sdk/client-s3";
const s3Client = new S3Client({
region: "auto",
endpoint: `https://${CF-ACCOUNT-ID}.r2.cloudflarestorage.com`, //TODO: replace
credentials: {
accessKeyId: `${ACCESS-KEY}`, //TODO: replace
secretAccessKey: `${ACCESS-SECRET}`, //TODO: replace
},
});
async function main() {
const response = await s3Client.send(
new PutBucketCorsCommand({
Bucket: "your-bucket-name", //TODO: replace
CORSConfiguration: {
CORSRules: new Array({
AllowedHeaders: ["content-type"], //this is important, do not use "*"
AllowedMethods: ["GET", "PUT", "HEAD"],
AllowedOrigins: ["*"],
ExposeHeaders: [],
MaxAgeSeconds: 3000,
}),
},
})
);
console.dir(repsonse)
}
main();执行 node cors.js
最后的返回结果:
{
'$metadata': {
httpStatusCode: 200,
requestId: undefined,
extendedRequestId: undefined,
cfId: undefined,
attempts: 1,
totalRetryDelay: 0
}
}现在就可以愉快的直接通过 presignedurl 上传 文件到 r2 的存储桶了