如何仅使用客户端 JavaScript 正确签署对 Amazon 的 ItemLookup 的 GET 请求?
Posted
技术标签:
【中文标题】如何仅使用客户端 JavaScript 正确签署对 Amazon 的 ItemLookup 的 GET 请求?【英文标题】:How to properly sign a GET request to Amazon's ItemLookup using client-side JavaScript only? 【发布时间】:2014-04-30 12:32:43 【问题描述】:这是我目前所拥有的:
function sha256(stringToSign, secretKey)
return CryptoJS.HmacSHA256(stringToSign, secretKey);
function getAmazonItemInfo(barcode)
var parameters =
"Service=AWSECommerceService&"
+ "AWSAccessKeyId=" + appSettings.amazon.accessKey + "&"
+ "Operation=ItemLookup&"
+ "ItemId=" + barcode
+ "&Timestamp=" + Date.now().toString();
var stringToSign =
"GET\n"
+ "webservices.amazon.com\n"
+ "/onca/xml\n"
+ parameters;
var signature = "&Signature=" + encodeURIComponent(sha256(stringToSign, appSettings.amazon.secretKey));
var amazonUrl =
"http://webservices.amazon.com/onca/xml?"
+ parameters
+ signature;
// perform a GET request with amazonUrl and do other stuff
当作为 HTTP GET 请求执行时,上述代码中 amazonUrl
的值会导致来自 Amazon 的以下响应:
<?xml version="1.0"?>
<ItemLookupErrorResponse xmlns="http://ecs.amazonaws.com/doc/2005-10-05/">
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>
The request signature we calculated does not match the signature you provided.
Check your AWS Secret Access Key and signing method. Consult the service
documentation for details.
</Message>
</Error>
<RequestId>[REMOVED]</RequestId>
</ItemLookupErrorResponse>
有用的链接:
ItemLookup - Product Advertising API Amazon Documentation
Example REST Requests
AWS Authentication Process
CryptoJS
【问题讨论】:
这可能也有帮助:github.com/livelycode/aws-lib/blob/master/examples/prod-adv.js 我相信您在 encodeURI 之前缺少 Base64 编码。 @David 我没有阅读亚马逊文档中关于 Base64 编码的任何内容,但我看到你的 php sn-p 做到了。您是如何确定它需要进行 Base64 编码的? 我忘记了我在哪里读到的,几年前我编写了我的库并一直在使用它,所以我不再担心任何低级的东西了。 【参考方案1】:我修改了你的代码,我得到了它的工作。
function sha256(stringToSign, secretKey)
var hex = CryptoJS.HmacSHA256(stringToSign, secretKey);
return hex.toString(CryptoJS.enc.Base64);
function timestamp()
var date = new Date();
var y = date.getUTCFullYear().toString();
var m = (date.getUTCMonth() + 1).toString();
var d = date.getUTCDate().toString();
var h = date.getUTCHours().toString();
var min = date.getUTCMinutes().toString();
var s = date.getUTCSeconds().toString();
if(m.length < 2) m = "0" + m;
if(d.length < 2) d = "0" + d;
if(h.length < 2) h = "0" + h;
if(min.length < 2) min = "0" + min;
if(s.length < 2) s = "0" + s
var date = y + "-" + m + "-" + d;
var time = h + ":" + min + ":" + s;
return date + "T" + time + "Z";
function getAmazonItemInfo(barcode)
var PrivateKey = "";
var PublicKey = "";
var AssociateTag = "";
var parameters = [];
parameters.push("AWSAccessKeyId=" + PublicKey);
parameters.push("ItemId=" + barcode);
parameters.push("Operation=ItemLookup");
parameters.push("Service=AWSECommerceService");
parameters.push("Timestamp=" + encodeURIComponent(timestamp()));
parameters.push("Version=2011-08-01");
parameters.push("AssociateTag=" + AssociateTag);
parameters.sort();
var paramString = parameters.join('&');
var signingKey = "GET\n" + "webservices.amazon.com\n" + "/onca/xml\n" + paramString
var signature = sha256(signingKey,PrivateKey);
signature = encodeURIComponent(signature);
var amazonUrl = "http://webservices.amazon.com/onca/xml?" + paramString + "&Signature=" + signature;
console.log(amazonUrl);
我用作参考的 javascript 的标头。
<script src="hmac-sha256.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/components/enc-base64-min.js"></script>
<script src="amazon.js"></script>
你需要修改它的一部分,因为我改变了一些参数并且没有引用你的“app”对象。
我做了什么来修复它(据我所知)。
参数必须按字母顺序排列。我将它们放在一个数组中,然后对它们进行排序。我通过与 & 号的连接来跟进这一点。
我修改了 sha256 函数以返回 RAW sha256 的 base64。在它返回小写的十六进制位之前,这是不正确的。
我打算在编码之前添加一个 base64,但现在 sha256 处理了所有的签名。
日期格式不正确。它返回一个纪元时间戳而不是字符串时间戳。我拼凑了一个简单的时间戳选项。
此代码还要求您包含用于 CryptoJS 的 Base64 库。
【讨论】:
这看起来不错,但我正在寻找一个 JavaScript 解决方案。 更新为 Javascript。【参考方案2】:使用this Node.js library for AWS。它甚至包括专门用于产品广告 API 的 an example。
【讨论】:
【参考方案3】:在大卫的出色回答的基础上,我做了一些调整。下面的解决方案使用moment.js和crytpo-js,可用于按关键字搜索项目。我使用amazon scratch-pad 来帮助构建目标调用。我注意到了几件事:
便签本需要使用与您的associates account、“.com”、“.co.uk”等相同的位置。 您呼叫的端点必须与您的员工帐户位于同一国家/地区。 您使用的时间戳需要与您的员工帐户注册所在国家/地区的当地时间相匹配。const getAmazonItemInfo = (keywords) =>
let date = moment().startOf().add(-9, 'hours').format("YYYY-MM-DDThh:mm:ss.000") + 'Z'
let SecretKey = "GENERATED_IN_AFFILATES_ACCOUNT";
let AccessKey = "GENERATED_IN_AFFILATES_ACCOUNT";
let AssociateTag = "FOUND_IN_AFFILATES_ACCOUNT";
let parameters = [];
let url = 'webservices.amazon.co.uk' // UK account
//let url = 'webservices.amazon.com'// US account
parameters.push("AWSAccessKeyId=" + AccessKey);
parameters.push("Keywords=" + keywords);
parameters.push("Operation=ItemSearch");
parameters.push("SearchIndex=All");
parameters.push("ResponseGroup=" + encodeURIComponent('Images,ItemAttributes,Offers'));
parameters.push("Service=AWSECommerceService");
parameters.push("Timestamp=" + encodeURIComponent(date));
parameters.push("AssociateTag=" + AssociateTag);
parameters.sort();
let paramString = parameters.join('&');
let string_to_sign = "GET\n" + url + "\n" + "/onca/xml\n" + paramString
let signature = CryptoJS.HmacSHA256(string_to_sign, SecretKey);
signature = CryptoJS.enc.Base64.stringify(signature);
let amazonUrl = "http://" + url + "/onca/xml?" + paramString + "&Signature=" + signature;
return amazonUrl;
let keywords = 'iphone'
console.log(getAmazonItemInfo(keywords))
【讨论】:
以上是关于如何仅使用客户端 JavaScript 正确签署对 Amazon 的 ItemLookup 的 GET 请求?的主要内容,如果未能解决你的问题,请参考以下文章
如何仅使用 JavaScript 正确读取 json 文件 [重复]
如何创建仅使用客户端JavaScript的sharepoint数据表单web部件