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

Angular使用预签名URL上传文件至S3时遇CORS问题求助

Angular通过预签名URL向DigitalOcean Spaces上传文件遇CORS错误问题

我在Angular前端通过后端生成的预签名URL向DigitalOcean Spaces(兼容S3)上传文件时遇到CORS错误,但相同请求在Postman里能正常执行。

错误信息

Access to XMLHttpRequest at 'https://fra1.digitaloceanspaces.com/my-test-s3-bucket/a9da491a-cfaa-4532-bae6-43a515f5e657.doc?AWSAccessKeyId=DO00CPCLULU4MB9RHW2A&Content-Type=application%2Fmsword&Expires=1704439698&Signature=GT1PLU6sCqCeLe9nnb5GExs%2BWj4%3D' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

Angular上传代码

async upload(links: Sections<string[]>, files: Sections<File[]>) {
  const h = (file: File) => ({ 'Content-Type': file.type });
  console.log("links: ", links);
  console.log("files: ", files);

  return await Promise.all([
    ...files.information.map((file, i) =>
      this.http.put(links.information[i], file, { headers: h(file) }).toPromise()
    ),
  ]);
}

存储桶CORS配置

<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <ExposeHeader>ETag</ExposeHeader>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
<CORSRule>
    <AllowedOrigin>http://localhost:4200</AllowedOrigin>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <ExposeHeader>ETag</ExposeHeader>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>

排查与解决步骤

  • 核对预签名URL生成逻辑:后端生成预签名URL时,必须将请求中使用的Content-Type参数纳入签名范围,同时确保指定的HTTP方法为PUT。如果签名参数和实际请求不匹配,即使桶的CORS配置正确,也会触发CORS错误。
  • 简化并验证CORS配置:当前配置中两个规则存在重复,保留任意一个即可(比如仅保留允许http://localhost:4200的规则)。DigitalOcean Spaces的CORS配置修改后需要1-2分钟生效,修改后等待片刻再测试。也可以显式添加<AllowedHeader>Content-Type</AllowedHeader>,避免通配符匹配的潜在问题。
  • 调整Angular请求细节:避免文件类型获取不准确导致的头信息不匹配,可以尝试用'application/octet-stream'作为兜底,或者直接从预签名URL的查询参数中提取Content-Type值来设置请求头,确保和签名时的参数完全一致。也可以添加observe: 'response'选项查看完整响应头,确认CORS头部是否返回:
    this.http.put(links.information[i], file, { 
      headers: h(file),
      observe: 'response'
    }).toPromise()
    
  • 检查浏览器预检请求:打开浏览器开发者工具的网络面板,查看OPTIONS预检请求的响应状态和返回头。如果预检请求没有返回Access-Control-Allow-Origin等CORS头部,说明桶的CORS配置未正确生效。

内容的提问来源于stack exchange,提问作者Илья Никитин

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 23:42:32