web-dev-qa-db-fra.com

L'en-tête HTTP Amazon MWS SubmitFeed Content-MD5 ne correspond pas à Content-MD5 calculé par Amazon

Je sais que cette question n’est pas nouvelle, mais toutes les solutions que j’obtiens sont dans PHP ou mon problème est différent d’eux.

J'utilise l'API de flux MWS pour soumettre un fichier plat pour les mises à jour de prix et de quantité et obtenir toujours l'erreur suivante:

l'en-tête HTTP Content-MD5 que vous avez transmis pour votre flux ne correspond pas à Content-MD5 calculé pour votre flux


Je voudrais poser 3 questions ici: -

  1. Le paramètre ContentMD5Value est facultatif, comme indiqué dans la doc, mais si je ne l’ai pas transmis, il vous dira que vous devez entrer ContentMD5Value.

  2. Comme dans la doc la ContentFeed qui nous a été donnée à Amazon. Amazon crée contentMD5 pour ce fichier, puis compare cette valeur contentMD5 à la valeur contentMD5 que nous envoyons à Amazon.
    Si les deux correspondent, cliquez sur OK, sinon une erreur sera générée. Mais si je suppose que je n'enverrai pas le fichier, les mêmes erreurs que MD5 ne correspondent. Comment est-ce possible? Pour quel fichier calculent-ils le MD5? Parce que je n'ai pas envoyé le fichier dans ContentFeed.

  3. Si j'envoie le contentMD5 dans un en-tête ainsi que le paramètre et l'envoi de la ContentFeed dans le corps, j'obtiens toujours l'erreur.

Remarque: - J'envoie le contentMD5 dans un en-tête ainsi que dans un paramètre du formulaire à l'aide du module de requête, je calcule également la signature avec celui-ci, puis passe le corps de la variable contentFeed.

J'utilise JavaScript (Meteor), je calcule le md5 à l'aide du module crpyto.
Tout d’abord, je pense que mon md5 est faux, puis j’ai essayé avec un site Web en ligne qui me donnera le md5 pour un fichier le md5.

pour mon dossier c'est:

Valeur MD5: d90e9cfde58aeba7ea7385b6d77a1f1e
Base64Encodevalue: ZDkwZTljZmRlNThhWWhh2WhNzM4NWI2ZDc3YTFmMWU =

Le fichier plat que j'ai téléchargé pour les mises à jour de prix et de quantité: -

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

J'ai aussi calculé la signature en donnant ContentMD5Value lors du calcul de la signature.

FeedType: '_ POST_FLAT_FILE_PRICEANDQUANTITYONLY_UPDATE_DATA_'

Au fur et à mesure que j'ai lu la documentation à ce sujet, j'ai passé l'en-tête MD5 dans les en-têtes et également l'envoyer en tant que paramètre.

Amazon doc dit:

Auparavant, Amazon MWS acceptait le hachage MD5 en tant qu'en-tête Content-MD5 Au lieu d'un paramètre. En le passant en tant que paramètre, vous vous assurez que la valeur MD5 Fait partie de la signature de la méthode, ce qui empêche toute personne sur le réseau De modifier le contenu du flux.

Amazon MWS acceptera toujours un en-tête Content-MD5, qu'un paramètre ContentMD5Value soit inclus ou non. Si un en-tête et un paramètre Sont utilisés et qu'ils ne correspondent pas, vous recevrez une erreur InvalidParameterValue.

J'utilise le module request pour les requêtes http.

Je transmets toutes les clés requises, identifiant du vendeur, etc. sous forme de module de requête et transmets le corps FeedContent.

J'ai essayé d'envoyer le fichier comme suit:

La méthode pour submitFeed est la suivante: -

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);
        }
    }))

La méthode qui appelle Amazon submitFeedAPI est la suivante: -

    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');

La fonction mwsReqProcessor est la suivante: -

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

Méthode de génération de 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;

};

J'ai aussi essayé avec ce qui suit: -

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

J'ai également essayé sans JSON et envoyer directement le flux de lecture de fichier dans le corps , C'est-à-dire:

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

Mais la même erreur vient à chaque fois:

l'en-tête HTTP Content-MD5 que vous avez transmis pour votre flux ne correspond pas à Content-MD5 calculé pour votre flux

Je souhaite savoir où je me trompe ou quelle est la bonne façon de soumettre une API de flux et d'envoyer le fichier à l'aide du module de requête.

J'ai également essayé avec le code indiqué sur MWS de générer le MD5 mais la même erreur Se produisait à chaque fois.

Mon fichier .txt comme suit:

 sku quantité prix 
 TP-T2-00-M 2 

Toute aide est très appréciée

26
Parveen yadav

Désolé pour la réponse tardive, mais pourquoi ne pas essayer d’envoyer le fichier en plusieurs parties dans la requête form-data et d’autres queryStrings dans la propriété 'qs' du module request. Vous pouvez soumettre la demande comme suit: -

 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
Ravi verma

enfin, j'ai eu la solution, comme Ravi l'a dit plus haut. En fait, il y a quelques points que je veux clarifier ici pour vous tous qui sont confrontés au même problème: -

1) Amazon marketplace API Doc ne fournit pas les informations et l'exemple appropriés. Même je suppose que la documentation n'est pas mise à jour. Comme dans doc ils ont dit que la valeur du paramètre ContentMD5Value est optionnelle, voici le lien pour doc: -

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

Vous pouvez vérifier à cet endroit qu'ils indiquent clairement que le champ n'est pas obligatoire, mais si vous ne passez pas, ils indiqueront que vous devez transmettre la valeur du contenu MD5.

Donc c'est faux. ContentMD5 est un attribut requis.

2) Dans le même document, ils ont indiqué que vous deviez envoyer des données de fichier, que ce soit un fichier XML ou un fichier plat dans le nom de clé du champ, à savoir FeedContent.

Mais ce n’est pas nécessaire non plus, vous pouvez envoyer le fichier avec n’importe quel nom sans que Ait besoin de donner la clé FeedContent pour le fichier dont vous avez juste besoin d’envoyer le fichier En flux continu.

3) Ils donneront la même erreur de contentMD5 ne correspond pas à la météo que vous envoyez le fichier ou pas parce que s'ils ne trouvent pas le fichier que le contenu MD5 que vous envoyez ne correspondra pas à cela. SO si vous obtenez l'erreur ContentMD5 ne correspond pas, vérifiez les points suivants: -

1) Vérifiez que vous générez le bon code MD5 pour votre fichier, vous pouvez vérifier si vous générez le bon code ou non en utilisant le code Java indiqué dans la documentation. Vous pouvez l'obtenir à partir du lien: -

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

2) Ne vous fiez pas aux sites Web en ligne pour générer le codage MD5 et le hachage.

3) Si votre MD5 correspond au MD5 généré à partir du code Java, il est clair que votre MD5 est correct, il n’est donc pas nécessaire de changer cela.

4) Une fois que votre MD5 est correct et après cela également si vous obtenez la même erreur qui est: -

L'en-tête HTTP Amazon MWS SubmitFeed Content-MD5 ne correspond pas à la valeur Content-MD5 calculée par Amazon.

ContentMD5 ne correspond pas. Vous devez vérifier uniquement et uniquement le mécanisme de téléchargement de votre fichier. Parce que le fichier que vous envoyez à Amazon n'est pas correct ou que vous ne l'envoyez pas correctement.

Vérifier le téléchargement du fichier: -

Pour vérifier si vous envoyez ou non le bon fichier, vous devez vérifier avec: -

1) Vous devez envoyer les paramètres requis tels que sellerId, marketplaceId, AWSAccessKey, etc. en tant que paramètres de requête.

2) Vous devez envoyer le fichier sous la forme de données de formulaire en plusieurs parties, si vous utilisez le module de requête de node.js, vous pouvez voir le code ci-dessus fourni par Ravi.

3) vous devez définir l'en-tête comme étant seulement: -

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

Pas besoin d'envoyer l'en-tête en tant que chunked ou tabulation séparée etc. parce que je n'en ai plus besoin, ils me confondent même parce que quelque part quelqu'un écrit utilise cet en-tête sur un autre endroit où quelqu'un écrit utilise cet en-tête. Donc, comme je suis finalement en mesure de soumettre cette API, je n'ai besoin d'aucun en-tête plutôt que d'application/x-www-form-urlencoded.

Exemple:-

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.

Le code pour créer le contenuMD5 est: -

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

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

Comme je suis confronté au problème qui est parce que j'utilise le formulaire et les données de formulaire simultanément via le module de requête, je convertis donc les données de formulaire avec qs (chaîne de requête) et le fichier sous forme de données en plusieurs parties.

Ainsi, de cette manière, vous pouvez soumettre avec succès l’API pour le flux de soumission.

Toutes les questions sont les bienvenues Merci 

4
Parveen yadav

Amazon nécessite le hachage md5 du fichier en codage base64.

Votre code:

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

suppose à tort que toString() d'une readStream produira le contenu du fichier, alors que cette méthode est héritée de Object et génère la chaîne '[object Object]'

Le codage Base64 de cette chaîne always produit le 'FEGnkJwIfbvnzlmIG534uQ==' que vous avez mentionné.

Si vous voulez bien lire et encoder le hachage, vous pouvez procéder comme suit:

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

qui fournit des résultats équivalents à l'extrait PHP suivant:

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

Probablement, je suis trop tard, mais voici les points clés pour C #: 

1) Les formulaires multipartes ne fonctionnaient pas du tout. Terminé avec ce qui suit (simplifié): 

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

2) À propos de 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) À propos de 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);
}
0
arudoy