亚马逊MWS SubmitFeed Content-MD5 HTTP标头与亚马逊计算的Content-MD5不匹配

Par*_*dav 26 node.js amazon-mws meteor

我知道这个问题并不新鲜,但我得到的所有解决方案都是在PHP中,或者我的问题与它们不同.

我正在使用MWS Feed API提交价格和数量更新的平面文件,并始终收到以下错误:

您为Feed传递的Content-MD5 HTTP标头与我们为您的Feed计算的Content-MD5不匹配


我想在这里问3个问题: -

  1. ContentMD5Value参数是doc中给出的可选参数,但如果我没有传递,那么它会说你必须输入ContentMD5Value.

  2. 正如ContentFeed我们给予亚马逊的doc那样.Amazon contentMD5为该文件创建,然后将该contentMD5值与contentMD5我们发送给Amazon 的值进行比较.
    如果两者都匹配则OK,否则会抛出错误.但是如果假设我不发送文件,那么同样的错误也会与MD5不匹配.怎么可能?他们在为哪个文件计算MD5?因为我还没有发送文件ContentFeed.

  3. 如果我发送contentMD5标题以及参数并发送ContentFeed正文,我仍然会收到错误.

注意: - 我contentMD5使用请求模块发送标题以及表单中的参数,并使用它计算签名然后传入contentFeed正文.

我正在使用JavaScript(Meteor),我使用crpyto模块计算md5 .
首先,我认为我的md5是错的,但后来我尝试了一个在线网站,它会给我一个文件md5的md5.

对于我的文件是:

MD5值:d90e9cfde58aeba7ea7385b6d77a1f1e
Base64Encodevalue:ZDkwZTljZmRlNThhZWJhN2VhNzM4NWI2ZDc3YTFmMWU =

我从价格和数量更新下载的平面文件: -

https://sellercentral.amazon.in/gp/help/13461?ie=UTF8&Version=1&entries=0&

我在计算签名时也通过给ContentMD5Value出来计算签名.

的FeedType: '_ POST_FLAT_FILE_PRICEANDQUANTITYONLY_UPDATE_DATA_'

因为,我读了文档,我在标题中传递了MD5标题,并作为参数发送.

亚马逊医生说:

以前,亚马逊MWS接受MD5哈希作为Content-MD5标头而不是参数.将其作为参数传递可确保MD5值是方法签名的一部分,从而防止网络上的任何人篡改Feed内容.

无论是否包含ContentMD5Value参数,亚马逊MWS仍将接受Content-MD5标头.如果使用标头和参数,并且它们不匹配,您将收到InvalidParameterValue错误.

我正在使用request模块进行http请求.

我正在以请求模块的形式传递所有必需的密钥,卖方ID等,并传递FeedContent正文.

我尝试发送文件如下:

submitFeed的方法是: -

submitFeed : function(){
    console.log("submitFeedAPI running..");
    app  = mwsReport({auth: {sellerId:'A4TUFSCXD64V3', accessKeyId:'AKIAJBU3FTBCJUIZWF', secretKey:'Eug7ZbaLljtrnGKGFT/DTH23HJ' }, marketplace: 'IN'});
    app.submitFeedsAPI({FeedType:'_POST_FLAT_FILE_PRICEANDQUANTITYONLY_UPDATE_DATA_'},Meteor.bindEnvironment(function(err,response){
        if(err){
            console.log("error in submit feed...")
            console.log(err)
        }
        else{
            console.log("suuccess submit feed....")
            console.log(response);
        }
    }))
Run Code Online (Sandbox Code Playgroud)

调用Amazon submitFeedAPI的方法是: -

    var submitFeedsAPI =  function(options, callback){
        console.log("submitFeedsAPI running...");
    var fileReadStream = fs.createReadStream('/home/parveen/Downloads/test/testting.txt');
        var contentMD5Value = crypto.createHash('md5').update(file).digest('base64');

    var reqForm = {query: {"Action": "SubmitFeed", "MarketplaceId": mpList[mpCur].id, "FeedType":options.FeedType,"PurgeAndReplace":false,"ContentMD5Value":contentMD5Value}}; 
            mwsReqProcessor(reqForm, 'submitFeedsAPI', "submitFeedsAPIResponse", "submitFeedsAPIResult", "mwsprod-0000",false,file, callback);
    }


also try

    var fileReadStream = fs.createReadStream('/home/parveen/Downloads/test/testting.txt');
    var base64Contents = fileReadStream.toString('base64');
    var contentMD5Value = crypto.createHash('md5').update(base64Contents).digest('base64');
Run Code Online (Sandbox Code Playgroud)

mwsReqProcessor功能如下: -

 mwsReqProcessor = function mwsReqProcessor(reqForm, name, responseKey, resultKey, errorCode,reportFlag,file, callback) {

        reqOpt = {
            url: mwsReqUrl,
            method: 'POST',
            timeout: 40000,
            body:{FeedContent: fs.readFileSync('/home/parveen/feedContentFile/Flat.File.PriceInventory.in.txt')},
            json:true,
            form: null,
            headers: {
                // 'Transfer-Encoding': 'chunked',
                //'Content-Type': 'text/xml',
               // 'Content-MD5':'ZDkwZTljZmRlNThhZWJhN2VhNzM4NWI2ZDc3YTFmMWU=',
                // 'Content-Type': 'text/xml; charset=iso-8859-1'
                'Content-Type':'text/tab-separated-values;charset=UTF-8'
            },
        }
        reqOpt.form = mwsReqQryGen(reqForm);
        var r = request(reqOpt, function (err, res, body){
            console.log(err)
            console.log(res)
        })
        // var form  = r.form();
        //form.append('FeedContent',fs.createReadStream('/home/parveen/feedContent//File/Flat.File.PriceInventory.in.txt'))
    }
Run Code Online (Sandbox Code Playgroud)

mwsReqQryGen生成方法: -

mwsReqQryGen = function mwsReqQryGen(options) {
    var method     = (options && options.method) ? ('' + options.method) : 'POST',
        host       = (options && options.host)   ? ('' + options.host)   : mwsReqHost,
        path       = (options && options.path)   ? ('' + options.path)   : mwsReqPath,
        query      = (options && options.query)  ? options.query         : null,


        returnData = {
          "AWSAccessKeyId": authInfo.accessKeyId,
          "SellerId": authInfo.sellerId,
          "SignatureMethod": "HmacSHA256",
          "SignatureVersion": "2",
          "Timestamp": new Date().toISOString(),
           "Version":"2009-01-01",
        },
        key;

    if(query && typeof query === "object")
      for(key in query)
        if(query.hasOwnProperty(key)) returnData[key] = ('' + query[key]);

    if(authInfo.secretKey && method && host && path) {

      // Sort query parameters
      var keys = [],
          qry  = {};

      for(key in returnData)
        if(returnData.hasOwnProperty(key)) keys.push(key);

      keys = keys.sort();
      for(key in keys)
        if(keys.hasOwnProperty(key)) qry[keys[key]] = returnData[keys[key]];
      var sign = [method, host, path, qs.stringify(qry)].join("\n");
      console.log("..................................................")
      returnData.Signature = mwsReqSignGen(sign);

    }
//console.log(returnData); // for debug

return returnData;
Run Code Online (Sandbox Code Playgroud)

};

我也试过以下: -

reqOpt = {
    url: mwsReqUrl,
    method: 'POST',
    timeout: 40000,
    json:true,
    form: null,
    body:  {FeedContent: fs.createReadStream('/home/parveen/feedContentFile/Flat.File.PriceInventory.in.txt')},
    headers: {
        // 'Transfer-Encoding': 'chunked',
        //'Content-Type': 'text/xml',
       // 'Content-MD5':'ZDkwZTljZmRlNThhZWJhN2VhNzM4NWI2ZDc3YTFmMWU=',
        //   'Content-Type': 'text/xml; charset=iso-8859-1'
    },
}
Run Code Online (Sandbox Code Playgroud)

我也试过没有JSON并直接在正文中发送文件读取流,即:

reqOpt = {
    url: mwsReqUrl,
    method: 'POST',
    timeout: 40000,
    form: null,
    body:  fs.createReadStream('/home/parveen/feedContentFile/Flat.File.PriceInventory.in.txt'),
    headers: {
        // 'Transfer-Encoding': 'chunked',
        //'Content-Type': 'text/xml',
     //   'Content-MD5':'ZDkwZTljZmRlNThhZWJhN2VhNzM4NWI2ZDc3YTFmMWU=',
        //   'Content-Type': 'text/xml; charset=iso-8859-1'
    },
}
Run Code Online (Sandbox Code Playgroud)

但每次都会出现同样的错误:

您为Feed传递的Content-MD5 HTTP标头与我们为您的Feed计算的Content-MD5不匹配

我想知道我在哪里做错了,或者提交feed API和使用请求模块发送文件的正确方法是什么.

我还尝试使用MWS上给出的代码生成MD5,但每次都发生相同的错误.

我的.txt文件如下:

sku price   quantity
TP-T2-00-M      2

任何帮助深表感谢

Par*_*dav 4

最后我得到了拉维上面所说的解决方案。实际上,我想为所有面临同样问题的人澄清几点:-

  1. 亚马逊市场API 文档没有提供正确的信息和示例。即使我猜文档还没有更新。正如在文档中他们所说,ContentMD5Value 参数值在此页面上是可选的

    您可以在那里查看,他们清楚地提到该字段不是必需的,但如果您不通过,他们会给出您必须传递内容 MD5 值的错误。

    所以这是错误的。ContentMD5 是必需属性。

  2. 他们在同一个文档中说,您需要发送文件数据,无论其是字段键名称中的 xml 或平面文件,即FeedContent

    但这也不是必需的,您可以发送任何名称的文件,无需提供FeedContent文件的密钥,您只需在流中发送文件即可。

  3. 他们会给出同样的错误,即 contentMD5 与您发送的文件不匹配,因为如果他们没有找到文件,那么您发送的 contentMD5 将与该文件不匹配。因此,如果您收到ContentMD5 不匹配错误,请检查以下内容:-

    1. 检查您是否为文件生成了正确的 MD5 代码,您可以通过他们在 doc 上提供的 java 代码来检查您是否生成了正确的代码。您可以从此链接获取该信息

    2. 不要相信在线网站会生成 MD5 哈希值和 Base64 编码。

    3. 如果您的 MD5 与他们提供的 Java 代码生成的 MD5 相匹配,那么有一点很明显,您的 MD5 是正确的,因此无需对此进行更改。

    4. 一旦您的 MD5 正确,之后如果您收到相同的错误:-

      Amazon MWS SubmitFeed Content-MD5 HTTP 标头与 Amazon 计算的 Content-MD5 不匹配

ContentMD5 不匹配。您只需要检查文件上传机制。因为现在您发送给亚马逊的文件要么不正确,要么您没有以正确的方式发送它。

检查文件上传情况

要检查您是否发送了正确的文件,您需要检查以下内容:-

  1. 您需要发送所需的参数,如 sellerId、marketplaceId、AWSAccessKey 等作为查询参数。

  2. 如果您使用的是node.js的请求模块,您需要将form-data中的文件作为multipart发送,那么您可以看到Ravi给出的上述代码。

  3. 您只需将标题设置为:-

    '内容类型':'application/x-www-form-urlencoded'

不需要以分块或制表符分隔等方式发送标头,因为我不再需要它们,它们甚至让我感到困惑,因为有人写的地方使用这个标头,而有人写的其他地方使用这个标头。 所以最后,当我准备提交这个 API 时,我不需要任何标头,而是 application/x-www-form-urlencoded。

例子:-

reqOpt = {
   url: mwsReqUrl,
   method: 'POST',
   formData: {
      my_file: fs.createReadStream('file.txt')
  },
  headers: {
     'Content-Type': 'application/x-www-form-urlencoded'
  },
qs: { }// all the parameters that you are using while creating signature.
Run Code Online (Sandbox Code Playgroud)

创建 contentMD5 的代码是:-

var  fileData= fs.readFileSync('/home/parveen/Downloads/test/feed.txt','utf8');

var contentMD5Value = crypto.createHash('md5').update(fileData).digest('base64');
Run Code Online (Sandbox Code Playgroud)

因为我面临的问题是因为我通过请求模块同时使用表单和表单数据,所以我使用 qs(查询字符串)转换表单数据并将表单数据中的文件作为多部分。

这样就可以成功提交submit feed的API了。