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

浏览器JS通过PUT上传文件到GCS预签名URL出现CORS及签名错误求助

问题1:CORS错误解决方案

  • 根因:浏览器发起跨域PUT请求前会先发送OPTIONS预检请求,你当前的CORS配置仅放开了PUT、POST方法,未包含OPTIONS,导致预检请求被GCS拒绝,没有返回正确的CORS头。
  • 修复步骤:
    1. 修改CORS配置,添加OPTIONS到允许的方法列表,修改后代码如下:
BUCKET.cors = [
        {
            "origin": ["*"],
            "responseHeader": [
                "Content-Type",
                "x-goog-resumable"],
            "method": ['PUT', 'POST', 'OPTIONS'],
            "maxAgeSeconds": 3600
        }
    ]
BUCKET.patch()
  1. 配置更新后GCS会有最长5分钟的缓存时间,等待缓存失效后再测试,或者测试时清除浏览器缓存避免旧策略影响。生产环境建议将origin的*替换为实际业务域名,提高安全性。

问题2:SignatureDoesNotMatch签名错误解决方案

  • 根因:从错误返回的CanonicalRequest可以看到,实际请求的Content-Type是image/png,但你生成预签名URL时指定的content_type是application/octet-stream,V4签名要求签名时的参数和实际请求参数严格一致,二者不匹配导致签名校验失败。
  • 修复方案二选一即可:

方案1:生成预签名URL时动态传入文件实际的Content-Type

前端请求预签名接口时,将本地文件的type属性传给后端,后端生成签名时使用该值,示例代码:

# 前端传过来的content_type参数
content_type = request.args.get("content_type")
url = blob.generate_signed_url(
        version="v4",
        expiration=datetime.timedelta(minutes=15),
        method="PUT",
        content_type=content_type,
)

方案2:前端上传时强制指定Content-Type和生成时一致

在fetch请求中添加请求头,强制指定Content-Type为application/octet-stream,避免浏览器自动设置,修改后代码如下:

const {signed_url} = await(await fetch(baseUrl + "/upload/signed?blob_name=" + path, {
  credentials: "include",
})).json();
// 上传到谷歌云存储
const uploadRes = await fetch(signed_url, {
  method: "PUT", 
  body: file,
  headers: {
    'Content-Type': 'application/octet-stream'
  }
})

注意:不要使用CORS插件绕过校验,该方式仅本地临时测试可用,生产环境无法使用,且会隐藏真实的配置问题。

内容的提问来源于stack exchange,提问作者Jan Wirth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 06:24:02