MWS Post Request with Google Scripts

2019-07-12 18:26发布

I am trying to make a post request through google scripts to amazon to collect information.

We are trying to get our orders to MWS and transfer them to sheets automatically.

I got to the last step which is signing the request.

A few things I wasnt sure about:

  1. They say we use the secret key for hashing,I only see a client secret and an access key id, which do I use?
  2. Do I add the URL as part of whats getting signed? On the MWS Scratch pad they add this as shown:

POST mws.amazonservices.com /Orders/2013-09-01

Does it have to be on separate lines does it need post and the rest of the stuff. Its a little unclear.?

  1. I read online that the sha256 byte code gets base64 encoded, not the string literal, is that true?
  2. I tried to hash the string that amazon gave to me with an online tool and compare it to the hash they provided and the base64 encode, thing matched. I tried decoding as well, nothing matched

Can someone please send me an example that works, so I can understand what happens and how it works?

Thank you!

Below is what I have so far:

function POSTRequest() {

  var url = 'https:mws.amazonservices.com/Orders/2013-09-01?';

  var today = new Date();
  var todayTime = ISODateString(today);

  var yesterday = new Date();
  yesterday.setDate(today.getDate() - 1);
  yesterday.setHours(0,0,0,0);
  var yesterdayTime = ISODateString(yesterday); 

  var dayBeforeYesterday = new Date();
  dayBeforeYesterday.setDate(today.getDate() - 2);
  dayBeforeYesterday.setHours(0,0,0,0);
  var dayBeforeYesterdayTime = ISODateString(dayBeforeYesterday); 

  var unsignedURL = 
  'POST\r\nhttps:mws.amazonservices.com\r\n/Orders/2013-09-01\r\n'+
  'AWSAccessKeyId=xxxxxxxxxxx' +
  '&Action=ListOrders'+
  '&CreatedAfter=' + dayBeforeYesterdayTime +
  '&CreatedBefore' + yesterdayTime +
  '&FulfillmentChannel.Channel.1=AFN' +
  '&MWSAuthToken=xxxxxxxxxxxx'+
  '&MarketplaceId.Id.1=ATVPDKIKX0DER' +
  '&SellerId=xxxxxxxxxxx'+
  '&SignatureMethod=HmacSHA256'+
  '&SignatureVersion=2'+
  '&Timestamp='+ ISODateString(new Date) + 
  '&Version=2013-09-0';

  var formData = {
        'AWSAccessKeyId' : 'xxxxxxxxx',
        'Action' : "ListOrders",
        'CreatedAfter' : dayBeforeYesterdayTime,
        'CreatedBefore' : yesterdayTime,
        'FulfillmentChannel.Channel.1' : 'AFN',
        'MWSAuthToken' : 'xxxxxxxxxxxx',
        'MarketplaceId.Id.1' : 'ATVPDKIKX0DER',
        'SellerId' : 'xxxxxxxxxx',
        'SignatureMethod' : 'HmacSHA256',
        'SignatureVersion' : '2',
        'Timestamp' : ISODateString(new Date),
        'Version' : '2013-09-01',
        'Signature' : calculatedSignature(unsignedURL)

      };

   var options = {
     "method" : "post",
     "muteHttpExceptions" : true,
     "payload" : formData
   };


  var result = UrlFetchApp.fetch(url, options);
  writeDataToXML(result);
  Logger.log(result);


  if (result.getResponseCode() == 200) {
  writeDataToXML(result);
  }
}




function calculatedSignature(url) {
var urlToSign = url;
var secret = "xxxxxxxxxxxxxxxxxxx";
var accesskeyid = 'xxxxxxxxxxxxxxx';

  var byteSignature = Utilities.computeHmacSha256Signature(urlToSign, secret);
// convert byte array to hex string
var signature = byteSignature.reduce(function(str,chr){
  chr = (chr < 0 ? chr + 256 : chr).toString(16);
  return str + (chr.length==1?'0':'') + chr;
},'');


  Logger.log("URL to sign: " + urlToSign);
  Logger.log("");
  Logger.log("byte " + byteSignature);
  Logger.log("");
  Logger.log("reg " + signature);

var byte64 =  Utilities.base64Encode(byteSignature)
Logger.log("base64 byte " + Utilities.base64Encode(byteSignature));
  Logger.log("");
Logger.log("base64 reg " + Utilities.base64Encode(signature)); 

 return byte64;
}

1条回答
倾城 Initia
2楼-- · 2019-07-12 19:12

Step 1, creating the string to be signed

The string_to_sign is the combination of the following:

  • The string POST followed by a NEWLINE character
  • The name of the host, mws.amazonservices.com, followed by a NEWLINE
  • The API URL, often just /, or somthing like /Orders/2013-09-01, followed by a NEWLINE
  • An alphabetical list of all parameters except Signature in URL encoding, like a=1&b=2, not followed by anything

The minimum parameters seem to be the following:

  • AWSAccessKeyId is a 20-character code provided by Amazon
  • Action is the name of your API call, like GetReport
  • SellerId is your 14-character seller ID
  • SignatureMethod is HmacSHA256
  • SignatureVersion is 2
  • Timestamp is a date like 20181231T23:59:59Z for one second before new year UTC
  • Version is the API version like 2013-09-01
  • additional parameters may be needed for your call, depending on the value of Action

Please note:

  • The NEWLINE character is just "\n", not "\r\n"
  • The name of the host should not include "https://" or "http://"
  • The Signature parameter is necessary for the actual call later (see step 3), but is not part of the string_to_sign.

Your string_to_sign should now look somewhat like this:

POST
mws.amazonservices.com
/Orders/2013-09-01
AWSAccessKeyId=12345678901234567890&Action=ListOrders&CreatedAfter .... &Version=2013-09-01

Step 2, signing that string

  • Calculate a SHA256 hash of above string using the 40-character Secret Key
  • Encode this hash using Base64
  • In Pseudocode: signature = Base64encode( SHA256( string_to_sign, secret_key ))

Step 3, send the call

Send a HTTPS POST request, using the full alphabetical list of parameters, now including above signature as Signature somewhere in the middle, because you need to keep ascending alphabetical order.

https://mws.amazonservices.com/Orders/2013-09-01?AWSAccessKeyId....Version=2013-09-01

Step 4, processing the result

You should be getting two things back: a response header and a XML document. Be sure to evaluate the HTTP status in the header as well as all contents of the XML document. Some error messages are hidden deeply in XML while HTTP returns "200 OK".

Step 5, Advanced Stuff

If you use calls that require you to send a document, like SendFeed, you need to do the following additional steps:

  • Calculate the MD5 hash of your document
  • Encode this hash using Base64
  • In Pseudocode: contentmd5= Base64encode( MD5( document ))
  • Add Content-Type: text/xml (or whatever fits your document) as HTTP header
  • Add Content-MD5: plus the base64 encoded hash as HTTP header
查看更多
登录 后发表回答