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

时间:2012-04-26 08:19:09

标签: delphi amazon-s3 content-type indy 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);

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

  

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

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

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

有什么想法吗?

2 个答案:

答案 0 :(得分: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)将字符集附加到内容类型(如果它是'text'且它还没有)。它不应该在这些情况下更改内容类型,因为内容类型是要签名的字符串的一部分,因此在签名后更改它会使签名无效。

答案 1 :(得分:0)

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