Подтвердить что ты не робот

Amazon MWS SubmitFeed Content-MD5 HTTP-заголовок не соответствует Content-MD5, рассчитанному Amazon

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

Я использую API-интерфейс канала MWS для отправки плоского файла для обновлений цены и количества и всегда получаю следующую ошибку:

HTTP-заголовок Content-MD5, который вы передали для своего канала, не соответствовал Content-MD5, который мы рассчитали для вашего фида


Я хотел бы задать здесь 3 вопроса:

  • Параметр ContentMD5Value является необязательным, как указано в doc, но если я не передал это, то он скажет, что вы должны ввести ContentMD5Value.

  • Как и в doc ContentFeed, который мы даем Amazon. Amazon создает contentMD5 для этого файла, а затем сравнивает это значение contentMD5 со значением contentMD5, которое мы отправляем на Amazon.
    Если оба соответствуют, то ОК, в противном случае он выдает ошибку. Но если предположить, что я не буду отправлять файл, то также будут появляться те же ошибки, что MD5 не соответствует. Как это возможно? В каком файле они рассчитывают MD5? Потому что я не отправил файл в ContentFeed.

  • Если я отправлю contentMD5 в заголовок, а также параметр и отправив ContentFeed в тело, я все равно получаю ошибку.

Примечание. - Я отправляю contentMD5 в заголовке, а также в параметрах в форме, используя модуль запроса, а также вычисляя подпись с этим, а затем передаю ContentFeed в теле.

Я использую JavaScript (Meteor), я вычисляю md5 с помощью модуля crpyto.
Во-первых, я думаю, что мой md5 ошибается, но затем я попробовал с онлайн-сайта, который даст мне md5 для файла md5.

для моего файла:

Значение MD5: d90e9cfde58aeba7ea7385b6d77a1f1e
   Base64Encodevalue: ZDkwZTljZmRlNThhWWJhN2VhNzM4NWI2ZDc3YTFmMWU =

Плоский файл, который я скачал для обновления цены и количества: -

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

Я вычислил подпись также, указав ContentMD5Value при расчете сигнатуры.

FEEDTYPE: '_ POST_FLAT_FILE_PRICEANDQUANTITYONLY_UPDATE_DATA _

Как, я прочитал документацию для этого, я передал MD5-заголовок в заголовках, а также отправлю как параметр.

Amazon doc говорит:

Ранее Amazon MWS принимала хэш MD5 как заголовок Content-MD5 вместо параметра. Передача его в качестве параметра гарантирует, что MD5 значение является частью сигнатуры метода, которая препятствует тому, чтобы на сеть от вмешательства в содержимое фида.

Amazon MWS по-прежнему будет принимать заголовок Content-MD5, независимо от того, Включен параметр ContentMD5Value. Если и заголовок, и параметр используются, и они не совпадают, вы получите Ошибка InvalidParameterValue.

Я использую модуль request для http-запросов.

Я передаю все необходимые ключи, идентификатор продавца и т.д. в форме модуля запроса и передавая 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);
        }
    }))

Метод, который вызывает 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');

Функция 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'))
    }

Метод генерации 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;

};

Я также пробовал со следующим: -

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'
    },
}

Я также пробовал без 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'
    },
}

Но такая же ошибка возникает каждый раз:

HTTP-заголовок Content-MD5, который вы передали для своего канала, не соответствовал Content-MD5, который мы рассчитали для вашего фида

Я хочу знать, где я делаю неправильно, и как правильно подать API-интерфейс и отправить файл с помощью модуля запроса.

Я также пробовал с кодом, указанным в MWS, для генерации MD5, но тот же ошибка возникала каждый раз.

Мой .txt файл следующим образом:

sku price   quantity
TP-T2-00-M      2

Любая помощь очень ценится

4b9b3361

Ответ 1

Прошу прощения за поздний ответ, но почему бы вам не попробовать отправить файл в multipart в запрос данных формы и другие queryStrings в свойстве "qs" модуля запроса. Вы можете отправить запрос следующим образом: -

 reqOpt = {
   url: mwsReqUrl,
   method: 'POST',
   formData: {
      my_file: fs.createReadStream('file.txt')
  },
  headers: {
     'Content-Type': 'application/x-www-form-urlencoded'
  },
  qs: { 
     AWSAccessKeyId: '<your AWSAccessKeyId>',
     SellerId: '<your SellerId>',
     SignatureMethod: '<your SignatureMethod>',
     SignatureVersion: '<your SignatureVersion>',
     Timestamp: '<your Timestamp>',
     Version: '<your Version>',
     Action: 'SubmitFeed',
     MarketplaceId: '<your MarketplaceId>',
     FeedType: '_POST_FLAT_FILE_PRICEANDQUANTITYONLY_UPDATE_DATA_',
     PurgeAndReplace: 'false',
     ContentMD5Value: '<your file.txt ContentMD5Value>',
     Signature: '<your Signature>'
 }
}

request(reqOpt, function(err, res){

})

Ответ 2

Наконец, я получил решение, как сказал Рави. На самом деле есть несколько моментов, которые я хочу прояснить для всех, кто сталкивается с одной проблемой: -

1) База данных Amazon API doc не дает правильной информации и примера. Даже я думаю, что документация не обновляется. Как и в документе, они сказали, что значение параметра ContentMD5Value является необязательным, здесь ссылка для документа: -

http://docs.developer.amazonservices.com/en_US/feeds/Feeds_SubmitFeed.html

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

Так что это неправильно. ContentMD5 - обязательный атрибут.

2) Они сказали в том же документе, что вам нужно отправить данные файла по погоде за его xml или плоским файлом в поле имени ключа, то есть FeedContent.

Но это также не нужно, вы можете отправить файл с любым именем no необходимо предоставить ключ FeedContent для файла, который вам просто нужно отправить файл в потоке.

3) Они будут давать ту же ошибку contentMD5, которая не соответствует погоде, которую вы отправляете, или нет, потому что если они не нашли файл, чем отправленный вами контент, который вы отправляете, это не будет соответствовать. SO, если вы получаете ошибку ContentMD5, не проверяйте следующее: -

1) Убедитесь, что вы генерируете правильный код MD5 для своего файла, вы можете проверить, генерируете ли вы правильный код или нет, там java-код, который они указали в документе. Вы можете получить это из ссылки: -

http://docs.developer.amazonservices.com/en_US/dev_guide/DG_MD5.html

2) Не доверяйте веб-сайтам для генерации хеша MD5 и кодировки base64.

3) Если ваш MD5 сопоставляется с MD5, сгенерированным из кода Java, который они дали, чем одно, ясно, что ваш MD5 прав, поэтому нет необходимости в этом изменять.

4) Как только ваш MD5 будет прав, а затем, если вы получите ту же ошибку, что: -

Amazon MWS SubmitFeed Content-MD5 HTTP-заголовок не соответствует Content-MD5, рассчитанный Amazon

ContentMD5 не соответствует. Если вам нужно только проверить и только вы загружаете файл. Поскольку теперь файл, который вы отправляете на Amazon, не является правильным, или вы не отправляете его правильно.

Проверка загрузки файла: -

Для проверки того, хотите или нет, вы отправляете нужный файл, который необходимо проверить со следующими параметрами: -

1) Вам необходимо отправить необходимые параметры, такие как sellerId, marketplaceId, AWSAccessKey и т.д. в качестве параметров запроса.

2) Вам необходимо отправить файл в форме-данных как multipart, если вы используете модуль запроса node.js, чем вы можете видеть приведенный выше код Ravi.

3) вам нужно установить заголовок только: -

'Content-Type': 'application/x-www-form-urlencoded'

Не нужно посылать заголовок как chunked или tab, разделенные и т.д., потому что я больше не нуждаюсь в них, они даже путают меня, потому что где-то кто-то пишет этот заголовок на другом месте, кто-то пишет этот заголовок. Итак, наконец, поскольку я abel для отправки этого 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.

Код для создания contentMD5: -

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

var contentMD5Value = crypto.createHash('md5').update(fileData).digest('base64');

Как я столкнулся с проблемой, потому что я использую форму и данные формы одновременно через модуль запроса, поэтому я конвертирую свои данные формы с qs (строкой запроса) и файлом в виде данных как multipart.

Таким образом, вы можете успешно отправить API для подачи фида.

Любые запросы приветствуются Спасибо

Ответ 3

Amazon требует хэш файл md5 в кодировке base64.

Ваш код:

var fileReadStream = fs.createReadStream('/path/to/file.txt');
var file = fileReadStream.toString('base64'); //'[object Object]'
var contentMD5Value = crypto.createHash('md5').update(file).digest('base64');

ошибочно предполагает, что a readStream toString() приведет к созданию содержимого файла, когда на самом деле этот метод наследуется от Object и выдает строку '[object Object]'.

Base64-encoding, строка всегда создает 'FEGnkJwIfbvnzlmIG534uQ==', о котором вы упомянули.

Если вы хотите правильно прочитать и закодировать хэш, вы можете сделать следующее:

var fileContents = fs.readFileSync('/path/to/file.txt'); // produces a byte Buffer
var contentMD5Value = crypto.createHash('md5').update(fileContents).digest('base64'); // properly encoded

который предоставляет результаты, эквивалентные следующему фрагменту PHP:

$contentMD5Value = base64_encode(md5_file('/path/to/file.txt', true));

Ответ 4

Возможно, я опоздал, но вот ключевые моменты для С#:

1) Составные данные формы не работали вообще. Закончено со следующим (упрощенно):

HttpContent content = new StringContent(xmlStr, Encoding.UTF8, "application/xml");
HttpClient client = new HttpClient();
client.PostAsync(query, content)

2) О query:

UriBuilder builder = new UriBuilder("https://mws.amazonservices.com/");
NameValueCollection query = HttpUtility.ParseQueryString(builder.Query);

query["AwsAccessKeyId"] = your_key_str;
query["FeedType"] = "_POST_ORDER_FULFILLMENT_DATA_";
... other required params
query["ContentMD5Value"] = Md5Base64(xmlStr);

builder.Query = query.ToString();
query = builder.ToString();

3) О Md5base64

public static string Md5Base64(string xmlStr)
{
  byte[] plainTextBytes = Encoding.UTF8.GetBytes(xmlStr);
  MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider();
  byte[] hash = provider.ComputeHash(plainTextBytes);
  return Convert.ToBase64String(hash);
}