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

使用Indy调用Shopify生成的Google Storage认证URL时遇403错误求助

问题分析与解决

问题描述

从Shopify获取了存储批量操作结果的Google Storage认证URL,在浏览器中粘贴该URL可正常获取jsonl响应,但使用Indy组件发起GET请求时收到403错误,错误信息显示SignatureDoesNotMatch。

认证URL

https://storage.googleapis.com/shopify-tiers-assets-prod-us-east1/l9qx25bn40srq20ihwremefeaa81?GoogleAccessId=assets-us-prod%40shopify-tiers.iam.gserviceaccount.com&Expires=1680018264&Signature=g8tFS3W%2FR2O6GfU74XCVttX954dcdycDPvoHklRnuUHAjpNwyxkwNsnK40r6%2FaxRAWL3X8XdWsBmBVLV4o94YiJTwg9yG7RQLIgJyytr3Rmx3ei1nPClRFQuE1Opm%2Fx1nhQXStTGs10BqQ98rqWgNhdG%2BSMqA2KB1QdYA6e1qzfDd%2F1VjSuI21ntQJswgVy0M5cY%2FPKo8%2FR%2F1U8K95V%2FjpXX12t9pgKpdU1axi0N0EpCzcFsgBMna2%2B0pT9qzS9ALV%2FzsE2QcFpcRyCIo1g7jX6apX1ZDlINYSWPzhqhQCZXV4bM0BmCIadIWOkjMT1YiMZecIoctTtzKgytsCXjdA%3D%3D

代码实现

uses IdHTTP, IdSSLOpenSSL;

procedure TfrmMain.btnDownloadFromGoogleClick(Sender: TObject);
var
  FileStream         : TFileStream;
  FURL, FResponseFile: string;
  SSL                : TIdSSLIOHandlerSocketOpenSSL;
  Api                : Tidhttp;
begin
  FURL          := 'https://storage.googleapis.com/shopify-tiers-assets-prod-us-east1/l9qx25bn40srq20ihwremefeaa81?GoogleAccessId=assets-us-prod%40shopify-tiers.iam.gserviceaccount.com&Expires=1680018264&Signature=g8tFS3W%2FR2O6GfU74XCVttX954dcdycDPvoHklRnuUHAjpNwyxkwNsnK40r6%2FaxRAWL3X8XdWsBmBVLV4o94Y' +
'iJTwg9yG7RQLIgJyytr3Rmx3ei1nPClRFQuE1Opm%2Fx1nhQXStTGs10BqQ98rqWgNhdG%2BSMqA2KB1QdYA6e1qzfDd%2F1VjSuI21ntQJswgVy0M5cY%2FPKo8%2FR%2F1U8K95V%2FjpXX12t9pgKpdU1axi0N0EpCzcFsgBMna2%2B0pT9qzS9ALV%2FzsE2QcFpcRyCIo1g7jX6apX1ZDlINYSWPzhqhQCZXV4bM0BmCIadIWOkjMT1YiMZecIoctTtzKgytsCXjdA%3D%3D';
  FResponseFile := 'bulkresponsegraphql.jsonl';
  FileStream    := TFileStream.create(FResponseFile, fmCreate);
  try
    Api := Tidhttp.create();
    try
      SSL := TIdSSLIOHandlerSocketOpenSSL.create(Api);
      try
        SSL.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];

        Api.Request.Clear;
        Api.IOHandler       := SSL;
        Api.HandleRedirects := True;

        try
          { same result with/out headers
Api.Request.CustomHeaders.AddValue('GoogleAccessId', 'assets-us-prod%40shopify-tiers.iam.gserviceaccount.com');
          Api.Request.CustomHeaders.AddValue('Signature', 'g8tFS3W%2FR2O6GfU74XCVttX954dcdycDPvoHklRnuUHAjpNwyxkwNsnK40r6%2FaxRAWL3X8XdWsBmBVLV4o94YiJTwg9yG7RQLIgJyytr3Rmx3ei1nPClRFQuE1Opm%2Fx1nhQXStTGs10BqQ98rqWgNhdG%2BSMqA2K' +
              'B1QdYA6e1qzfDd%2F1VjSuI21ntQJswgVy0M5cY%2FPKo8%2FR%2F1U8K95V%2FjpXX12t9pgKpdU1axi0N0EpCzcFsgBMna2%2B0pT9qzS9ALV%2FzsE2QcFpcRyCIo1g7jX6apX1ZDlINYSWPzhqhQCZXV4bM0BmCIadIWOkjMT1YiMZecIoctTtzKgytsCXjdA%3D%3D');
          Api.Request.CustomHeaders.AddValue('Expires', '1680018264');
}
          Api.Get(FURL, FileStream);

        except
          on e: EIdHTTPProtocolException do
            Memo1.Lines.add('HTTP status code: ' + inttostr(e.ErrorCode) + slinebreak + 'Error message: ' + e.Message + ', ' + e.ErrorMessage);
          on e: exception do
            Memo1.Lines.add(e.Message);
        end;
      finally
        SSL.free;
      end;

    finally
      Api.free;
    end;
  finally
    FileStream.free;
  end;
end;

错误响应

HTTP status code: 403
Error message: HTTP/1.0 403 Forbidden, <?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>GET


1680018264
/www.google.com/shopify-tiers-assets-prod-us-east1/l9qx25bn40srq20ihwremefeaa81</StringToSign></Error>
HTTP/1.0 403 Forbidden

问题根源

从错误返回的StringToSign字段可以看出,Google Storage计算签名时使用的路径是/www.google.com/shopify-tiers-assets-prod-us-east1/l9qx25bn40srq20ihwremefeaa81,但正确的路径应该是/shopify-tiers-assets-prod-us-east1/l9qx25bn40srq20ihwremefeaa81。这说明Indy组件在处理请求时错误地将主机名www.google.com附加到了请求路径前,导致签名验证失败。

解决方法

  1. 手动设置Request.Host:在发起请求前,明确设置请求的主机头,确保路径解析正确:
    Api.Request.Host := 'storage.googleapis.com';
    
  2. 检查URL拼接:将完整URL写成一行,避免拼接时引入意外的空格或换行符,确保URL字符串完全正确。
  3. 验证URL解析:使用TIdURI解析URL,确认路径部分无误:
    var URI: TIdURI;
    begin
      URI := TIdURI.Create(FURL);
      try
        // 输出路径确认是否正确
        ShowMessage(URI.Path);
      finally
        URI.Free;
      end;
    end;
    
  4. 调整SSL配置:确保TIdSSLIOHandlerSocketOpenSSL的配置正确,没有代理或自动修改请求的设置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 04:37:54