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

Spring RestClient调用GCS签名URL报403错误,RestTemplate等可正常工作

问题描述

尝试使用Spring Boot 3.4.4的RestClient通过预签名URL从Google Cloud Storage(GCS)下载文件,同一URL在RestTemplate和原生HttpURLConnection中均可正常工作,但使用RestClient时返回403权限错误。

错误信息

403 Forbidden: <?xml version='1.0' encoding='UTF-8'?><Error>
  <Code>SignatureDoesNotMatch</Code>
  <Message>Access denied.</Message>
  <Details>The request signature we calculated does not match the signature you provided</Details>
</Error>

当前使用的代码

var client = RestClient.builder()
    .defaultHeader("Host", "storage.googleapis.com")
    .defaultHeader("Accept-Encoding", "identity")
    .build();

Resource data = client.get()
    .uri(signedUrlString)  // 已验证可用的URL
    .header(HttpHeaders.CONTENT_LENGTH, "0")
    .retrieve()
    .body(Resource.class);

已尝试添加或移除Host、Accept-Encoding、Content-Length等请求头,但问题未解决,询问RestClient是否需要特定配置。


解决方案

GCS预签名URL的签名是严格绑定请求头、请求参数等内容生成的,RestClient默认的一些隐式行为会修改请求结构,导致签名校验失败,以下是关键修复点:

  1. 禁用自动重定向
    RestClient默认会自动处理3xx重定向,但GCS预签名URL仅对原始请求有效,重定向后的请求会触发签名不匹配。关闭自动重定向:
var client = RestClient.builder()
    .requestFactory(() -> {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setFollowRedirects(false);
        return factory;
    })
    .build();
  1. 移除手动添加的冗余请求头
    如果预签名URL生成时未包含Content-Length、Host这类头,手动添加会破坏签名校验的一致性。直接去掉这些自定义头,RestClient会自动从URL解析正确的Host头:
var client = RestClient.builder()
    .requestFactory(() -> {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setFollowRedirects(false);
        return factory;
    })
    .build();

Resource data = client.get()
    .uri(signedUrlString)
    .retrieve()
    .body(Resource.class);
  1. 明确禁用请求压缩
    RestClient可能默认添加Accept-Encoding: gzip,若预签名URL生成时未包含该头,会导致签名不匹配。可以强制设置不使用压缩:
var client = RestClient.builder()
    .requestFactory(() -> {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setFollowRedirects(false);
        return factory;
    })
    .defaultHeader(HttpHeaders.ACCEPT_ENCODING, "identity")
    .build();
  1. 避免URL二次编码
    确保传递给RestClient的URL没有被二次编码,可先将字符串URL转为URI对象再传入:
URI signedUri = URI.create(signedUrlString);
Resource data = client.get()
    .uri(signedUri)
    .retrieve()
    .body(Resource.class);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 13:26:07