You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用JavaScript上传大文件至S3时的CORS异常求助

问题描述

使用fetch API通过PUT方法结合AWS S3预签名URL上传本地文件时遇到CORS问题:

  • 上传30KB左右的小文件时,单次PUT请求可正常完成;
  • 上传2MB的大文件时,浏览器先发送OPTIONS预请求(返回200 OK,响应头包含Access-Control-Allow-Origin: *),但后续的实际PUT请求失败,且PUT请求的响应头中没有Access-Control-Allow-Origin字段。

已在S3存储桶中配置CORS策略,包含"Access-Control-Allow-Origin": "*"。代码如下:

let command = new PutObjectCommand({
    Body: "selectedfile",
    Bucket: "my bucket",
    Key: "filename"    
});
let signedurl = await getSignedUrl({
    region:"myregion",
    credentials:{accessKeyId:"mykey",secretAccessKey:"mykey"}}, command, {expiresIn:3600}
);
let response = await fetch(signedurl, {method: "PUT", body: "selectedfile"});
解决方案

1. 修正S3 CORS策略配置

S3的CORS策略需要明确允许PUT方法,确保实际请求响应能返回Access-Control-Allow-Origin。更新CORS策略为:

[
    {
        "AllowedHeaders": ["*"],
        "AllowedMethods": ["PUT", "OPTIONS"],
        "AllowedOrigins": ["*"],
        "ExposeHeaders": ["ETag"]
    }
]
  • AllowedMethods必须包含PUT和OPTIONS,覆盖预请求与实际请求的方法;
  • ExposeHeaders可选,若需要读取响应中的ETag等字段建议添加;
  • 保存配置后等待数分钟,让S3策略生效(配置可能存在延迟)。

2. 对齐预签名URL与请求的请求头

大文件上传时,浏览器会自动携带Content-Type等头信息,预签名URL需包含这些头的签名,否则S3会拒绝请求。修改代码如下:

// 替换为实际的File对象
const selectedFile = document.querySelector('input[type="file"]').files[0];
const contentType = selectedFile.type || 'application/octet-stream';

let command = new PutObjectCommand({
    Body: selectedFile,
    Bucket: "my bucket",
    Key: "filename",
    ContentType: contentType // 预签名时指定Content-Type
});

let signedurl = await getSignedUrl({
    region:"myregion",
    credentials:{accessKeyId:"mykey",secretAccessKey:"mykey"}}, command, {expiresIn:3600}
);

let response = await fetch(signedurl, {
    method: "PUT",
    body: selectedFile,
    headers: {
        'Content-Type': contentType // 请求时匹配预签名的Content-Type
    }
});

注意:原代码中Body为字符串"selectedfile"是笔误,需替换为实际的File对象。

3. 验证权限与预签名URL有效性

  • 确认生成预签名URL的IAM用户拥有s3:PutObject权限;
  • 检查预签名URL的有效期(你设置的3600秒正常),避免请求时URL已过期;
  • 核对URL中的Bucket、Key拼写是否正确。

4. 改用AWS SDK自动处理大文件上传

对于大文件,浏览器可能触发分块上传,手动预签名URL方式易出问题。建议使用AWS SDK的Upload类,它会自动处理分块、CORS与重试:

import { Upload } from "@aws-sdk/lib-storage";
import { S3Client } from "@aws-sdk/client-s3";

const selectedFile = document.querySelector('input[type="file"]').files[0];

const upload = new Upload({
    client: new S3Client({
        region:"myregion",
        credentials:{accessKeyId:"mykey",secretAccessKey:"mykey"}
    }),
    params: {
        Bucket: "my bucket",
        Key: "filename",
        Body: selectedFile,
        ContentType: selectedFile.type
    }
});

// 可选:监听上传进度
upload.on("httpUploadProgress", (progress) => {
    console.log(`上传进度:${progress.loaded}/${progress.total}`);
});

const result = await upload.done();

内容的提问来源于stack exchange,提问作者edward kim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 05:20:25