6

使用以下 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);

调用 UploadObject 时总是出错:

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

这仅在 Content-type 设置为 'text/plain'、'text/html' 或 text 任何内容时才会发生。使用完全相同的代码,如果您只是将内容类型更改为任何其他内容类型,例如“video/3gpp”,那么它会按预期工作且不会出错。正在上传的对象的实际内容不相关,并且与是否收到错误无关。

我已经通过 Delphi 中的 Indy 代码进行了跟踪,但我对为什么文本内容类型总是给出这个错误感到困惑。

有任何想法吗?

4

2 回答 2

4

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

Headers.Values['Content-type']:='text/plain; charset=ISO-8859-1';

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

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

于 2012-04-26T14:33:33.903 回答
0

我有同样的问题。我也使用 application/octet-stream 作为内容类型,但还是遇到了一些麻烦。后来,我发现存储桶名称必须小写(在美国标准区域,Amazon 允许使用大写或混合大小写名称定义存储桶;但是,这些存储桶无法通过 HTTP API(包括 TAmazonStorageService)访问。而不是未找到消息,我仍然收到 403 错误(未经身份验证的用户)。但是,我将名称更改为全小写,它工作正常。希望它有所帮助

于 2014-11-03T20:25:04.750 回答