Выполнение вызова HTTPS POST к Amazon в Delphi 2007

Мы используем Amazon Product Advertising API для переоценки на их сайте. Для тех, кто не знает, это в основном позволяет вам запрашивать базу данных Amazon без необходимости выполнять трудоемкие операции, такие как просмотр веб-страниц. Это работает очень хорошо для нас, или работает. Теперь они расформировывают этот API для продавцов и переводят нас на новый API в их сервисе MWS.

Насколько я вижу, звонки немного отличаются. Два очевидных различия заключаются в том, что API PA использует HTTP и GET, тогда как MWS использует HTTPS и POST.

Я не совсем уверен, что примеры в документации Amazon верны, поскольку они дают примеры создания запроса URL-адреса с хэш-подписью. Именно так мы успешно делали это в PA-API, где использовался метод GET. Но можете ли вы сделать это для POST? Я не думаю, что это возможно, хотя я могу ошибаться, и примеры именно это и подразумевают.

В любом случае, создание подписанного URL-адреса не работает! Поэтому я решил рассмотреть варианты использования HTTPS POST более низкого уровня в Delphi.

Я искал здесь, и есть несколько разных примеров, но я не могу заставить ни один из них работать правильно. В некоторых примерах, кажется, используется INDY 10, к сожалению, мы застряли (по причинам совместимости) на INDY 9. Я также просмотрел функции типа оболочки WININET, но я просто не могу получить результат, кроме исключения или ошибок.

Поэтому я здесь и прошу помощи.

Как сделать правильно отформатированный вызов Amazon MWS с помощью Delphi? Я пробовал примеры с таких страниц, как:

Как сделать HTTPS-запрос POST в 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

Я думаю, что моя проблема во всех примерах, которые я пробовал, я не знаю, как правильно настроить вызов, и, вероятно, поэтому я получаю ошибки Bad Request.

Таким образом, хорошее простое решение будет высоко оценено!


Ссылки на документацию и наблюдения:

Это руководство разработчика для 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. Он не принимает никаких параметров. Но его по-прежнему необходимо аутентифицировать и «подписать» с использованием учетных данных Amazon (идентификатор продавца, ключ доступа к 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;

Это основано на том, что Amazon ожидает получить в соответствии со своим блокнотом. Пользовательский агент в конце является необязательным, необязательным и не является частью процесса подписания:

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 неверный запрос». Странный.


person Trevor    schedule 14.02.2012    source источник
comment
Вероятно, вам следует сослаться на документацию службы, которую вы пытаетесь использовать, и выбрать очень конкретный тип запроса, который вы хотите реализовать. Сделайте так, чтобы кому-то было проще помочь, потому что в других случаях вы просто ждете кого-то, кто одновременно является разработчиком Delphi и продавцом Amazon. Если вы приложите достаточно усилий, я (и другие) могу попробовать это, даже если мы не продавцы на Amazon: например, есть ли какой-либо запрос, который можно сделать, не будучи продавцом? Предоставляет ли Amazon тестовые учетные записи, которые мы можем использовать?   -  person Cosmin Prund    schedule 15.02.2012
comment
Привет Космин. Спасибо за комментарий. Конечно, вы правы на 100%. Мой мозг был похож на замазку, пытаясь разобраться в этом, и теперь я понимаю, что ссылки на документацию помогут. У меня есть ссылки на работе. Когда я снова смогу публиковать сообщения (кажется, у меня есть ограничение на количество сообщений для новичков), я опубликую ссылки. К сожалению, это не тестовые аккаунты. И процесс подписания очень безопасен, используя идентификатор продавца, идентификатор доступа mws и секретный ключ для подписи звонка. Так что я понимаю, что это делает весь процесс докопаться до сути намного сложнее. Добавьте метку времени, и это станет еще сложнее. Но я опубликую ссылки на документы завтра.   -  person Trevor    schedule 15.02.2012
comment
Вы не должны публиковать снова, вы должны отредактировать текущий вопрос и добавить соответствующие детали. У вас есть ссылка edit под списком тегов для вашего вопроса. Вот как работает этот сайт: это не форум для дискуссий, это сайт вопросов и ответов.   -  person Cosmin Prund    schedule 15.02.2012
comment
Космин, мои извинения. Я действительно удивился, так как он сказал, что я отвечал на свой вопрос, когда сначала пытался, что мне показалось немного странным. Я предполагаю, что редактирую ответ Дорина с кодом, который я создал из его примера? Я сделаю это на этот раз и добавлю код, который у меня сейчас есть, к его ответу. Пожалуйста, посоветуйте, если это не способ сделать это. Еще раз извините, как я уже сказал, я здесь новичок и все еще чувствую, как это работает. Но спасибо за внимание к тому, как здесь все работает - последнее, что я хочу делать, это наступать на чьи-то пальцы, когда я ищу помощи. Спасибо.   -  person Trevor    schedule 15.02.2012


Ответы (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...

person Community    schedule 14.02.2012
comment
Привет Дорин. Спасибо за ответ. Я использовал ваш код, немного адаптировал его для вызовов ssl. Но все равно получите «плохой запрос». Я собирался опубликовать новый код, но я думаю, что есть ограничение на то, как быстро я могу опубликовать снова. Код находится на моем рабочем ноутбуке, я выложу его первым делом, когда доберусь до работы утром. Спасибо, Тревор. - person Trevor; 15.02.2012
comment
блин, ну... вернемся к документации по API... не пробовали включить перенаправления? - person ; 15.02.2012
comment
Дорин, я добавил свой код к вашему ответу и ссылки на документацию, которую я добавил к своему первоначальному вопросу. Я снова просмотрел документацию и знаю, что параметры и подпись верны, поскольку они работают в блокноте, а также когда я использую Fiddler для составления вызова. Так что это должно быть как-то связано с тем, как я создаю вызов из Delphi. - person Trevor; 15.02.2012
comment
Вот несколько вещей, которые нужно проверить: включите AllowCookies, назначьте диспетчер файлов cookie (odIdCookieManagerNewCooke, установите для VAccept значение true), включите HandleRedirects. Можете ли вы опубликовать трафик, созданный с помощью Fiddler? не забудьте скрыть конфиденциальную информацию. - person ; 15.02.2012

Просто чтобы все знали, что я отказался от попыток получить решение POST для этой работы - я был слишком разочарован тем, что не смог приблизиться к результату и потратил слишком много времени на программирование.

Вместо этого я вернулся к основам и изменил строку для подписи GET вместо POST, а затем создал параметризованный URL-адрес, который затем вызываю для получения результата XML.

Возможно, это не лучшее решение с технической или эстетической точки зрения, но оно работает!

Но спасибо всем за помощь и советы, ценю.

person Trevor    schedule 17.02.2012

Просто чтобы вы знали, я поделился вашей болью с этой проблемой, в конце концов перешел к формату GET, наконец, прочитал руководство

Отсортируйте компоненты строки запроса UTF-8 по имени параметра с естественным порядком байтов. Параметры могут поступать из GET URI или из тела POST (когда Content-Type имеет значение application/x-www-form-urlencoded).

Если вы установите тип контента, как указано выше в шапке, он будет работать

person Lowplex    schedule 24.08.2012