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

Google Cloud签名URL上传遇SignatureDoesNotMatch错误求助

Google Cloud签名URL上传文件遇SignatureDoesNotMatch错误排查

问题背景

无法通过Google Cloud签名URL完成文件上传,始终遇到SignatureDoesNotMatch错误。已尝试以下方案均未解决:

  • 切换V2签名替代V4
  • 添加/移除Content-Type
  • 改用Axios替代Fetch
  • Postman测试
  • POST+PUT结合x-goog-resumable:start
  • 修改存储桶CORS配置
  • 延长超时时间

签名URL生成代码

public static String generateV4PutObjectSignedUrl(String objectName) throws StorageException {
    // String projectId = "my-project-id";
    // String bucketName = "my-bucket";
    // String objectName = "my-object";

    Storage storage = StorageOptions.getDefaultInstance().getService();

    // Define Resource
    BlobInfo blobInfo = BlobInfo.newBuilder(BlobId.of("mybucket", objectName)).build();

    // Generate Signed URL
    Map<String, String> extensionHeaders = new HashMap<>();
    extensionHeaders.put("Content-Type", "application/octet-stream");

    URL url = storage.signUrl(
            blobInfo,
            15,
            TimeUnit.HOURS,
            Storage.SignUrlOption.httpMethod(HttpMethod.PUT),
            Storage.SignUrlOption.withExtHeaders(extensionHeaders),
            Storage.SignUrlOption.withV4Signature()
    );

    String urlS = url.toString();
    System.out.println("Generated PUT signed URL:"+urlS);
    return urlS;
}

存储桶CORS配置

[{"maxAgeSeconds": 3600000, "method": ["GET", "PUT", "OPTIONS", "POST"], "origin": ["LIVE", "http://localhost:8080", "http://0.0.0.0:8080"], "responseHeader": ["Content-Type", "x-goog-resumable"]}]

尝试的上传方式

Axios方式

const signedUrl = await fetch("$STORAGE_FUN/" + apkFile.name.replace(" ", "_")).then((res) => res.text());
await axios.put(signedUrl, apkFile);

Fetch方式

const put = await fetch(signedUrl, {
  method: 'PUT',
  headers: {'Content-Type': 'application/octet-stream'},
  body: apkFile
})

Curl方式

curl --location --request PUT 'https://storage.googleapis.com/mybucket/no-heroes-here.apk?GoogleAccessId=autodeploy@company.iam.gserviceaccount.com&Expires=1676643070&Signature=ZYU7CjzWRcKaqjOufUZ%2BkOJA%2FsB1vVpWBZAfpeUKIrmQRHJ6ZgXE7bwmqtaIWwBCbZv%2Fa1naYV3xC2OMqhpZ7ene46ZWS4JH%2FIvVn2U5SMBjYG38SrKqICLfj3l4sN%2BR39ijTxPwP4nWCpvMm39CxtCZAC6n5FovsNterZ7NqByXHP7YXgzOXeiBALabDv%2B%2BnclpVtoJ4K6h%2ByFKyQ6odzT0PTDIvpED4ph%2BIrdptwxraFFpLNL8k0ocAsd1zn9U4cxRrTTFCMzzMaXdhXRfVAtkSl5NW7BosdkRmgGtB%2FA1TEifea%2BnfXyXtbRaW7QG5TA9WxrA3VmHNMWz3At29A%3D%3D' \
-H 'Content-Type:' \
--data-binary '@/somepath/original/noheroeshere/no-heroes-here.apk'

错误信息

<?xml version='1.0' encoding='UTF-8'?>
<Error>
    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message>
    <StringToSign>GOOG4-RSA-SHA256
20230216T232500Z
20230216/auto/storage/goog4_request
338a1267c21129d5a991a59881cf42c0112f6cfd5cc067c162e0716adc059d5e</StringToSign>
    <CanonicalRequest>PUT
/mybucket/no-heroes-here.apk
X-Goog-Algorithm=GOOG4-RSA-SHA256&amp;X-Goog-Credential=autodeploy%40company.iam.gserviceaccount.com%2F20230216%2Fauto%2Fstorage%2Fgoog4_request&amp;X-Goog-Date=20230216T232500Z&amp;X-Goog-Expires=54000&amp;X-Goog-SignedHeaders=content-type%3Bhost
content-type:application/octet-stream
host:storage.googleapis.com

content-type;host
UNSIGNED-PAYLOAD</CanonicalRequest>
</Error>

问题解答

1. 代码中是否存在明显错误?

有两处关键不匹配点:

  • 生成签名URL时指定了Content-Type: application/octet-stream作为扩展头,但你尝试的curl请求中设置的是Content-Type:(空值),请求头与签名时的配置不一致,直接触发签名错误。
  • 使用Axios上传时,若直接传入apkFile(File对象),Axios会自动将Content-Type设为文件的实际类型(比如application/vnd.android.package-archive),而非签名时指定的application/octet-stream,同样会导致头信息不匹配。

2. 是否有办法调试签名错误,查看不匹配的具体内容?

错误返回中的<CanonicalRequest>和<StringToSign>就是核心调试依据:

  • 按照V4签名规则,自行重新计算请求的CanonicalRequest和StringToSign,与返回内容对比,即可定位不匹配项(如请求头、方法、路径、参数等)。
  • 开启存储桶的访问日志(Cloud Storage > 存储桶 > 日志记录),日志会记录完整的请求信息,包括实际发送的所有头和参数,方便与签名时的设置做对比。

3. 是否可能是服务账号的权限问题导致?

不会。SignatureDoesNotMatch是签名验证失败,与权限无关。若为权限问题,会返回PermissionDenied或AccessDenied错误。

4. 如果服务账号无效,签名URL是否还会生成?

会生成。签名URL的生成是本地用服务账号的私钥计算签名,无需与Google Cloud服务交互。只有当使用签名URL发起请求时,Google才会验证签名的有效性(包括服务账号是否存在、私钥是否匹配等)。


内容的提问来源于stack exchange,提问作者Laurent Meyer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 03:18:24