使用TAmazonStorageService.UploadObject在Content-type为'text/*'时出现SignatureDoesNotMatch错误

Mic*_*ick 6 delphi content-type indy amazon-s3 http-status-code-403

使用以下Delphi XE2(更新4)代码:

var
  ConInfo: TAmazonConnectionInfo;
  RespInfo: TCloudResponseInfo;
  Service: TAmazonStorageService;
  Content: TBytes;
  Headers: TStringList;
begin
  ConInfo:=TAmazonConnectionInfo.Create(self);
  ConInfo.AccountName:='YOUR ACCOUNT NAME';
  ConInfo.AccountKey:='YOUR ACCOUNT KEY';
  ConInfo.Protocol:='http';

  Service:=TAmazonStorageService.Create(ConInfo);
  RespInfo:=TCloudResponseInfo.Create;

  SetLength(Content, 128);
  FillMemory(@Content[0], 128, Byte('x'));

  Headers:=TStringList.Create;
  Headers.Values['Content-type']:='text/plain';
  if not Service.UploadObject('YOUR BUCKET', 'test.txt', Content, TRUE, nil, Headers, amzbaPrivate, RespInfo) then
    ShowMessage('Failed:' + RespInfo.StatusMessage);
Run Code Online (Sandbox Code Playgroud)

我总是在调用UploadObject时遇到错误:

失败:HTTP/1.1 403禁止 - 我们计算的请求签名与您提供的签名不匹配.检查您的密钥和签名方法.(SignatureDoesNotMatch)

仅当Content-type设置为'text/plain','text/html'或文本内容时才会发生这种情况.使用完全相同的代码,如果您只是将内容类型更改为任何其他内容类型,例如"video/3gpp",那么它将按预期工作且没有错误.上传的对象的实际内容不相关,与获取错误无关.

我已经通过Delphi中的Indy代码进行了跟踪,但是我很难理解为什么文本内容类型总是会出现这个错误.

有任何想法吗?

Mic*_*ick 4

如果将“; charset=ISO-8859-1”附加到 Content-Type 字符串,则它可以工作:

Headers.Values['Content-type']:='text/plain; charset=ISO-8859-1';
Run Code Online (Sandbox Code Playgroud)

单步执行代码,我看到 TIdEntityHeaderInfo.SetHeaders (IdHTTPHeaderInfo.pas) 中的 Content-Type 正在更改,该内容是从 TIdHTTPProtocol.BuildAndSendRequest (IdHTTP.pas) 调用的。

最终,问题似乎是 TIdEntityHeaderInfo.SetContentType (IdHTTPHeaderInfo.pas) 正在将字符集附加到内容类型(如果内容类型是“文本”并且还没有字符集)。在这些情况下不应该更改内容类型,因为内容类型是要签名的字符串的一部分,因此在签名后更改它会使签名无效。