You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用亚马逊SP-API PUT Item接口遇400/403错误,请求排查

NetSuite调用亚马逊SP-API PUT Item接口的问题

授权获取AccessToken(此步骤正常)

初始化参数:

var amz_url = "https://api.amazon.com/auth/o2/token",
    grant_type = "refresh_token",
    refresh_token = "{refreshtoken}",
    client_id = "amzn1.application-oa2-client.e87c20f1bc464aad8652******",
    client_secret = "46b8fbaef6285e8245b3a99d5a15ac8773e9d775bca44cb2220738a5f1*****";

授权请求代码:

let headers = ({
    'Content-Type': 'application/x-www-form-urlencoded',
    'Accept': '*/*',
    'Accept-Encoding': 'gzip, deflate, br',
    'Connection': 'keep-alive',
    'Cache-Control': 'no-cache',
    'Host': 'api.amazon.com'
});

let response = https.post({
    url: amz_url,
    body: { grant_type: '' + grant_type + '', refresh_token: '' + refresh_token + '', client_id: '' + client_id + '', client_secret: '' + client_secret + '' },
    headers: headers
});

log.debug("resp-code", response.code);
log.debug("resp-body", JSON.parse(response.body).refresh_token);

var accessToken = JSON.parse(response.body).access_token;

STS令牌获取与请求体构建

// Getting access token - END

// Getting STS token
var awsMainAccessKey = "AKIA4OOZPXxxxxxxx",
    awsMainSecretKey = "QbcC9g9ylrEGoy4aEUJ0uMkyq6xxxxxxx";

var stsResponse = stsRequest(awsMainAccessKey,awsMainSecretKey);

//Calculating timestamp in ISO 8601  format
var today = new Date();

var ISO8601Date = getXAmzDate();
log.debug('ISO 8601 date format ', ISO8601Date);

var bodyObj = {},
    condArray = [],
    itemArray = [],
    attributesObj = {},
    marketPlaceId = "A1F83G8C2ARO7P",
    sellerId = "A3F8NJ8FFYFH4O",
    productSKU = "TKR45UVDS";

请求体构建(生成的Payload Hash与亚马逊预期不符):

var bodyObj_final = {
    "productType": "LUGGAGE",
    "requirements": "LISTING",
    "attributes": {
      "condition_type": [
        {
          "value": "new_new",
          "marketplace_id": marketPlaceId
        }
      ],
      "item_name": [
        {
          "value": "AmazonBasics 16 Underseat Spinner Carry-On",
          "language_tag": "en_US",
          "marketplace_id": marketPlaceId
        }
      ]
    }
}

bodyObj.productType = "LUGGAGE";

condArray.push({
    "value": "new_new",
    "marketplace_id": marketPlaceId
});

itemArray.push({
    "value": "DC Basics 16 Inches rterdfertr",
    "language_tag": "en_UK",
    "marketplace_id": marketPlaceId
});

attributesObj.condition_type = condArray;

attributesObj.item_name = itemArray;

bodyObj.attributes = attributesObj;

var secToken = stsResponse.Credentials.SessionToken;

method = 'PUT';

var contenthash = "beaead3198f7da1e70d03ab969765e0821b24fc913697e929e726aeaebf0eba3";

标准化URI、签名构建与请求发送

// 标准化URI和查询字符串
canonical_uri = encodeURI('/listings/2021-08-01/items/' + sellerId +'/'+productSKU);

canonical_querystring = encodeURI('marketplaceIds')+'='+encodeURI('A1F83G8C2ARO7P');

var hmacsha256Data = CryptoJS.SHA256(JSON.stringify(bodyObj_final));
var payload_hash = CryptoJS.enc.Hex.stringify(hmacsha256Data);

canonical_headers = 'host:' + 'sellingpartnerapi-eu.amazon.com' + '\n' + 'x-amz-content-sha256:' + contenthash + '\n'+ 'x-amz-date:' + ISO8601Date + '\n'+ 'x-amz-security-token:' + secToken + '\n';

signed_headers = "host;x-amz-content-sha256;x-amz-date;x-amz-security-token";

log.debug('Payload payload_hash ', payload_hash);

// 硬编码的正确Hash,替换后请求可正常工作
var paylhash = "31ff10db41d2c210f7beb1adcd5b71c5ab2ec7ed13ad3972be88ff06db177aed";

canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + paylhash;

log.debug('URI String ', canonical_request);

/*************** TASK 2: CREATE THE STRING TO SIGN************* */
var monthStr = (today.getUTCMonth()+1),
    dayStr = today.getUTCDate();

var datestamp = today.getUTCFullYear() + '' + (monthStr>9?monthStr:('0'+monthStr)) + '' + (dayStr>9?dayStr:('0'+dayStr));

region = 'eu-west-1';
service = 'execute-api';
algorithm = 'AWS4-HMAC-SHA256';

var canonicalsha256Data = CryptoJS.SHA256(canonical_request);
var canonical_hash = CryptoJS.enc.Hex.stringify(canonicalsha256Data);

log.debug('canonical_hash is ', canonical_hash);

credential_scope = datestamp + '/' + region + '/' + 'execute-api' + '/' + 'aws4_request';
string_to_sign = algorithm + '\n' + ISO8601Date + '\n' + credential_scope + '\n' + canonical_hash;

log.debug('String to Sign ', string_to_sign);

/************* TASK 3: CALCULATE THE SIGNATURE *************/
secret_key = stsResponse.Credentials.SecretAccessKey;
access_key = stsResponse.Credentials.AccessKeyId;

signing_key = getSignatureKey(secret_key, datestamp, region, service);

var signingsha256Data = CryptoJS.HmacSHA256(string_to_sign, signing_key);

var signature = CryptoJS.enc.Hex.stringify(signingsha256Data);

log.debug('Final signature is ', signature);

/************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************/
authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature;

log.debug('authorization_header is ', authorization_header);

headers = { 
    'host': 'sellingpartnerapi-eu.amazon.com', 
    'x-amz-access-token': accessToken,
    'X-Amz-Security-Token': secToken,
    'x-Amz-Content-Sha256': contenthash,
    'x-amz-date': ISO8601Date, 
    'Authorization': authorization_header, 
    'Content-Type': 'application/json',
    'ACCEPT': '*/*'
}

/************** SEND THE REQUEST **************/
request_url = 'https://sellingpartnerapi-eu.amazon.com'+canonical_uri+'?' + canonical_querystring;

log.debug('Request URL is ', request_url);

var response_end = https.put({
    url: request_url,
    headers: headers,
    body : bodyObj
});

log.debug('Response Code is ', response_end.code); 
log.debug('Response is ', response_end.body); 

遇到的问题

  • 自行生成的Payload Hash与亚马逊预期不符,只有硬编码正确的paylhash时请求才能正常执行,否则返回403错误
  • 使用自定义Hash时,请求返回400错误:{ "errors": [ { "code": "InvalidInput", "message": "Invalid Input", "details": "" } ] }

排查建议

  • 请求体一致性验证:计算Hash用的是bodyObj_final,但实际发送的是bodyObj,两者结构不一致(比如bodyObj_final有requirements字段,bodyObj没有),这会导致Hash和实际请求体不匹配。必须保证计算Hash的对象与发送的请求体完全相同。
  • JSON序列化细节:JSON.stringify的输出要严格符合亚马逊的要求,比如键的顺序、是否有多余空格。可以手动序列化请求体,用在线SHA256工具计算Hash,和代码生成的对比,确认是否一致。
  • 请求头与签名匹配:检查canonical_headers中的头名称大小写,比如x-amz-security-token在签名中是小写,但实际请求头是X-Amz-Security-Token,大小写不匹配会导致签名验证失败。同时确保signed_headers的顺序与canonical_headers一致。
  • Payload Hash头对应:x-Amz-Content-Sha256头的值应该是代码生成的payload_hash,而不是硬编码的contenthash,否则头中的Hash与实际请求体Hash不匹配,触发403。
  • URI标准化检查:确认canonical_uri的编码是否符合亚马逊规范,亚马逊要求Canonical URI使用未编码的路径(除了必须编码的特殊字符),避免过度编码。
  • 时间戳有效性:确保ISO8601Date和datestamp是当前UTC时间,且格式严格符合YYYYMMDD'T'HHMMSS'Z',请求发送时间与签名中的时间戳差不能超过5分钟。

内容的提问来源于stack exchange,提问作者Gopi nadendla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 15:57:19