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

Google Storage可恢复分块上传CORS异常:跨域允许头缺失

问题原因与解决方案

1. 初始POST请求(创建会话)无CORS头的原因

你生成签名URL时,仅指定了x-goog-resumable扩展头,但没有将请求中要发送的Origin头加入签名的扩展头列表。GCS对签名URL的请求有严格要求:所有在请求中携带的自定义头(包括Origin)必须在签名时通过withExtHeaders声明,否则GCS不会返回CORS相关响应头。

修复代码

修改签名URL生成逻辑,将Origin头加入withExtHeaders:

val signedUrl = storage
    .signUrl(
        BlobInfo.newBuilder(BlobId.of(contentType.bucket, objectName)).build(),
        15,
        TimeUnit.MINUTES,
        Storage.SignUrlOption.httpMethod(HttpMethod.POST),
        Storage.SignUrlOption.withExtHeaders(
            mapOf(
                "x-goog-resumable" to "start",
                "Origin" to origin // 加入请求要发送的Origin值
            ),
        ),
        Storage.SignUrlOption.signWith(storageUploadCredentials),
        Storage.SignUrlOption.withV4Signature(),
    )
    .toString()

如果你的Origin是动态多域名,可以将Origin的签名值设为*,同时配合桶的CORS配置允许对应域名,不过需确认SDK版本支持通配符头的签名规则。

2. 后续PUT请求(上传块)无CORS头的原因

初始POST响应返回的location是GCS生成的会话URL,这个URL的CORS处理完全依赖桶的CORS配置,而非签名URL规则。你需要确保桶的CORS配置允许PUT方法,并且包含你的请求Origin。

示例桶CORS配置(JSON格式)

[
  {
    "origin": ["你的Origin域名"],
    "method": ["POST", "PUT", "OPTIONS"],
    "responseHeader": ["Content-Type", "x-goog-resumable", "Access-Control-Allow-Origin"],
    "maxAgeSeconds": 3600
  }
]

必须包含OPTIONS方法以支持浏览器预检请求;responseHeader可直接用"*"允许所有响应头,简化配置。

3. 错误POST请求返回CORS头的原因

向会话URL发送POST请求时,GCS返回405(方法不允许),此时GCS会优先触发CORS逻辑——错误响应场景下,GCS会自动根据桶的CORS配置返回对应头;而正确请求(初始POST创建会话、PUT上传块)因签名URL未包含Origin头(初始POST)或桶CORS配置不匹配(PUT),所以未返回CORS头。


内容的提问来源于stack exchange,提问作者Vojtěch

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 10:25:21