【问题标题】:Making an HTTPS POST call to Amazon in Delphi 2007在 Delphi 2007 中对 Amazon 进行 HTTPS POST 调用
【发布时间】:2012-03-05 22:49:22
【问题描述】:

我们使用亚马逊产品广告 API 在他们的网站上进行重新定价。对于那些不知道它的人来说,它基本上可以让您查询亚马逊数据库,而无需执行诸如抓取网页之类的耗时操作。它对我们非常有效,或者已经有效。他们现在正在为卖家解散这个 API,并在他们的 MWS 服务中将我们转移到一个新的 API。

据我所知,这些调用略有不同。两个明显的区别是 PA API 使用 HTTP 和 GET,而 MWS 使用 HTTPS 和 POST。

我不完全确定亚马逊文档中的示例是否正确,因为它们提供了创建为哈希签名 URL 请求的示例。这就是我们过去在使用 GET 方法的 PA-API 上成功执行此操作的方式。但是你可以为 POST 做到这一点吗?我不认为这是可能的,尽管我可能是错的,这肯定是例子所暗示的。

无论如何,创建签名 URL 是行不通的!所以我决定看看在 Delphi 中使用某种较低级别的 HTTPS POST。

我在这里搜索过,有几个不同的例子,但我无法让它们中的任何一个正常工作。一些示例似乎使用 INDY 10,不幸的是,我们被困在 INDY 9 上(出于兼容性原因)。我还查看了 WININET 包装器类型函数,但除了异常或错误之外,我无法返回结果。

这就是我在这里寻求帮助的原因。

如何使用 Delphi 对亚马逊 MWS 进行格式正确的调用?我尝试过以下页面中的示例:

How to make an HTTPS POST request in Delphi?

等等等等所有我能找到的!

但我收到了类似“错误请求”(异常)之类的错误。

我曾尝试使用 Fiddler(如其他地方所建议的那样)来查看正在发生的事情,但我还不能完全理解它(尽管我可以在其中编写一个有效的调用!)

所以我正在寻找一些指示或方向。我真的不想升级 INDY 或添加新库。我只想保持原样并使用我可用的东西。我们使用的是 D2007。

为了了解需要什么,我需要进行这种调用(GetServiceStatus 是最简单的):

POST /Products/2011-10-01?AWSAccessKeyId=<ACCESSKEY>
  &Action=GetServiceStatus
  &SellerId=<SELLERID>
  &SignatureVersion=2
  &Timestamp=2012-02-14T13%3A26%3A42Z
  &Version=2011-10-01
  &Signature=dtAvv595blmv%2FnV0h2Yr5bCGzKYXid0hkOuCmZOb3bc%3D
  &SignatureMethod=HmacSHA256

到这个端点:

https://mws.amazonservices.co.uk/Products/2011-10-01

我认为我的问题在于我尝试过的所有示例我不知道如何正确设置调用,这可能是我收到错误请求错误的原因。

所以,一个不错的简单解决方案将不胜感激!


文档链接和观察:

这是 API 的开发者指南:

https://images-na.ssl-images-amazon.com/images/G/02/mwsportal/doc/en_US/bde/MWSDeveloperGuide._V161846143_.pdf

这是我们将使用的 API 的特定部分(取代当前的产品广告 API):

https://images-na.ssl-images-amazon.com/images/G/02/mwsportal/doc/en_US/bde/MWSDeveloperGuide._V161846143_.pdf

这里最基本的函数是GetServiceStatus函数。它不带任何参数。但是,它仍然需要使用来自亚马逊的凭证(卖家 ID、MWS 访问密钥和密钥(用于生成签名)进行身份验证和“签名”。我的感觉是,如果我可以让最简单的功能正常工作,那么其余的将随之而来。但是身份验证问题使找到解决方案变得如此困难。没有测试帐户。而且时间戳(以及因此调用的签名)会过期几分钟。

还有一个“迁移指南”:

https://images-na.ssl-images-amazon.com/images/G/02/mwsportal/doc/en_US/products/MWSProductsApiMigrationGuide._V140058392_.pdf

但此文档确实包含一些错误。例如,端点不正确。


我的最新代码包括 ssl、cookie 管理器等:

var
  LHTTP                : TIdHTTP;
  IdSSLIOHandlerSocket : TIdSSLIOHandlerSocket;
  IdCookieManager      : TIdCookieManager;
  LParams              : TStringList;
  LResponse            : string;

begin
  IdCookieManager:=TIdCookieManager.Create(self);
  IdSSLIOHandlerSocket:=TIdSSLIOHandlerSocket.Create(self);
  with IdSSLIOHandlerSocket do begin
    SSLOptions.Method := sslvSSLv3;
  end;

  LHTTP := TIdHTTP.Create(Self);
  with LHTTP do begin
    CookieManager:=IdCookieManager;
    AllowCookies:=true;
    IOHandler:=IdSSLIOHandlerSocket;
    Request.ContentType:='text/xml';
    Port:=443;
    HandleRedirects:=true;
    Host:='mws.amazonservices.co.uk';
    ProtocolVersion:=pv1_1
  end;


  LParams := TStringList.Create;
  try
    LParams.Add('AWSAccessKeyId=<ACCESSKEY>');
    LParams.Add('Action=GetServiceStatus');
    LParams.Add('SellerId=<SELLERID>)');
    LParams.Add('SignatureVersion=2');
    LParams.Add('Timestamp=2012-02-15T13%3A00%3A07Z');
    LParams.Add('Version=2011-10-01');
    LParams.Add('Signature=viPlDAbzEBwlTAwq4hNaZi%2Fa1Klf7qIXIP%2BKUsOcJTI%3D');
    LParams.Add('SignatureMethod=HmacSHA256');
    LResponse:=LHTTP.Post('https://mws.amazonservices.co.uk/Products/2011-10-01?', LParams);
    ShowMessage( LResponse );
  except
    on E: Exception do
      ShowMessage('ouch! ' + E.Message );
  end;
  LHTTP.Free;
  IdSSLIOHandlerSocket.Free;
  IdCookieManager.Free;
end;

这是基于亚马逊期望收到的暂存器。最后的用户代理是可选的,不是必需的,也不是签名过程的一部分:

POST /Products/2011-10-01?AWSAccessKeyId=<ACCESSID>
  &Action=GetServiceStatus
  &SellerId=<SELLERID>
  &SignatureVersion=2
  &Timestamp=2012-02-15T13%3A00%3A07Z
  &Version=2011-10-01
  &Signature=viPlDAbzEBwlTAwq4hNaZi%2Fa1Klf7qIXIP%2BKUsOcJTI%3D
  &SignatureMethod=HmacSHA256 HTTP/1.1
Host: mws.amazonservices.co.uk
x-amazon-user-agent: AmazonJavascriptScratchpad/1.0 (Language=Javascript)
Content-Type: text/xml

我试图从 Fiddler 获取信息,但它没有显示来自该软件的任何流量,但它必须与 Amazon 通信才能获得“400 bad request”错误。奇怪。

【问题讨论】:

  • 您可能应该链接到您尝试使用的服务的文档,并选择您想要实现的非常具体的查询类型。让某人尽可能容易地提供帮助,因为其他方式您只是在等待既是 Delphi 开发人员又是亚马逊卖家的人。如果您付出足够的努力,即使我们不是亚马逊卖家,我(和其他人)也可能会尝试一下:例如,是否有 any 可以在没有卖家的情况下进行查询?亚马逊是否提供我们可以使用的测试账户?
  • 嗨科斯敏。感谢您的评论。当然,你是 100% 正确的。我的大脑就像油灰一样试图解决这个问题,我现在意识到文档链接会有所帮助。我有工作中的链接。当我可以再次发布时(似乎我对新手的帖子有限制)我会发布链接。可悲的是,他们没有测试帐户。并且签名过程非常安全,使用卖家 ID、mws 访问 ID 和密钥来签署电话。所以我很感激这使得深入了解这个问题的整个过程变得更加困难。添加一个时间戳,它变得更难了。但我明天会发布文档链接。
  • 您不应该“再次发布”,您应该编辑当前问题并添加相关详细信息。您的问题的标签列表下有一个edit 链接。这就是这个网站的运作方式:它不是一个讨论论坛,而是一个问答网站。
  • 科斯敏,我很抱歉。我确实想知道,因为它确实说我在最初尝试时正在回答我自己的问题,我觉得这有点奇怪。我假设我使用从他的示例中创建的代码来编辑 Dorins 答案?这次我会这样做,并将我现在拥有的代码附加到他的回复中。如果这不是这样做的方法,请提出建议。再次抱歉,就像我说我是新来的一样,仍然对它的工作方式有所了解。但是感谢您对这里的工作方式的提醒 - 我想做的最后一件事就是在我寻求帮助时踩到任何人的脚趾。谢谢。

标签: delphi amazon-mws


【解决方案1】:

只是为了让你知道,我分享了你的痛苦与这个问题,最终转到了 GET 格式,最后阅读了手册

使用自然字节顺序按参数名称对 UTF-8 查询字符串组件进行排序。参数可以 来自 GET URI 或 POST 正文(当 Content-Type 为 application/x-www-form-urlencoded 时)。

如果您在标题中设置上述内容类型,它将起作用

【讨论】:

    【解决方案2】:

    只是为了让大家知道我放弃了尝试让 POST 解决方案来完成这项工作 - 我对无法更接近结果并浪费太多编程时间感到非常沮丧。

    相反,我回到了基础,将字符串更改为 GET 而不是 POST,然后创建了一个参数化的 URL,然后我调用它来获取 XML 结果。

    也许在技术上或美学上不是最好的解决方案,但是,嘿,它行得通!

    但感谢大家的帮助和建议,不胜感激。

    【讨论】:

      【解决方案3】:

      我会使用 TIdHTTP,在 HTTPOptions 中使用您的凭据(如果适用)进行设置,然后执行以下操作:

      procedure ...
      var
        LHTTP: TIdHTTP;
        LParams: TStringList;
        LResponse: string;
      begin
        LHTTP := TIdHTTTP.Create;
        LParams := TStringList.Create;
        try
          // setup params, basically you're doing key-value pairs that will be encoded in the post
          // as KEY1=VALUE1&key2=value2&KEY3=value3, etc.
          // in the URL, stuff after ? are parameters
          // you don't have to worry about encoding parameters, indy will do it for you
          LParams['AWSAccessKeyId'] := '<ACCESSKEY>';
          LParams['Action'] := 'GetServiceStatus';
          LParams['SellerId'] := '<SELLERID>'
          LParams['SignatureVersion'] := '2';
          // adjust timestamp
          LParams['Timestamp'] := '2012-02-14T13%3A26%3A42Z';
          LParams['Version'] := '2011-10-01'
          // adjust signature...
          LParams['Signature'] := 'dtAvv595blmv%2FnV0h2Yr5bCGzKYXid0hkOuCmZOb3bc%3D';
          LParams['SignatureMethod'] := 'HmacSHA256';
          LResponse := LHTTP.Post('https://mws.amazonservices.co.uk/Products/2011-10-01', LParams);
          ShowMessage( LResponse );
        except
          on E: Exception do
            ShowMessage('ouch! ' + E.Message );
        end;
      end;
      

      我认为您需要将“/Products/2011-10-01”替换为您要搜索的日期,即“/Products/2012-02-14”等等...

      另外,如果我没记错的话,SSL 库是必需的......

      【讨论】:

      • 嗨多林。谢谢回复。我已经使用了您的代码,对 ssl 调用进行了一些调整。但仍然得到“错误的要求”。我打算发布新代码,但我认为再次发布的速度有限制。代码在我的工作笔记本电脑上,早上上班时我会第一时间发布。谢谢,特雷弗。
      • 该死的,好吧...返回 api 文档...必须尝试启用重定向?
      • Dorin,我已将我的代码添加到您的答案中,并将链接添加到我添加到原始问题的文档中。我再次浏览了文档,我知道参数和签名是正确的,因为它们在暂存器中以及当我使用 Fiddler 编写调用时也是如此。所以这与我从 Delphi 创建调用的方式有关。
      • 这里有几件事要测试:启用 AllowCookies,分配一个 cookiemanager(odIdCookieManagerNewCooke,将 VAccept 设置为 true),启用 HandleRedirects。您可以发布使用 Fiddler 生成的流量吗?不要忘记隐藏敏感信息。
      猜你喜欢
      • 1970-01-01
      • 2013-01-13
      • 1970-01-01
      • 2017-05-03
      • 2012-10-28
      • 1970-01-01
      • 1970-01-01
      • 2020-01-25
      • 1970-01-01
      相关资源
      最近更新 更多