web-dev-qa-db-fra.com

chercher un post avec des données de formulaire multipart

Je vais chercher une URL comme ceci:

fetch(url, {
  mode: 'no-cors',
  method: method || null,
  headers: {
    'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
    'Content-Type': 'multipart/form-data'
  },
  body: JSON.stringify(data) || null,
}).then(function(response) {
  console.log(response.status)
  console.log("response");
  console.log(response)
})

Mon API s'attend à ce que les données soient de multipart/form-data donc j'utilise content-type de ce type ... Mais elle me donne une réponse avec le code d'état 400.

Qu'est ce qui ne va pas avec mon code?

57
aryan

Vous définissez le Content-Type sur multipart/form-data, mais vous utilisez ensuite JSON.stringify sur les données du corps, qui renvoie application/json. Vous avez une incompatibilité de type de contenu.

Vous devrez encoder vos données sous la forme multipart/form-data au lieu de json. Habituellement, multipart/form-data est utilisé lors du téléchargement de fichiers et est un peu plus compliqué que application/x-www-form-urlencoded (qui est la valeur par défaut pour les formulaires HTML).

La spécification de multipart/form-data peut être trouvée dans RFC 1867 .

Pour un guide sur la manière de soumettre ce type de données via javascript, voir here .

L'idée de base est d'utiliser l'objet FormData (non pris en charge dans IE <10):

function sendData(url, data) {
  var formData  = new FormData();

  for(var name in data) {
    formData.append(name, data[name]);
  }

  fetch(url, {
    method: 'POST',
    body: formData
  }).then(function (response) {
     ...
  });
}

Pour https://muffinman.io/uploading-files-using-fetch-multipart-form-data/ assurez-vous que pas pour définir l'en-tête Content-Type. Le navigateur le définira pour vous, y compris le paramètre boundary.

106
rossipedia

Je travaillais récemment avec IPFS et ai travaillé sur cela. Un exemple de curl permettant à IPFS de télécharger un fichier ressemble à ceci:

curl -i -H "Content-Type: multipart/form-data; boundary=CUSTOM" -d $'--CUSTOM\r\nContent-Type: multipart/octet-stream\r\nContent-Disposition: file; filename="test"\r\n\r\nHello World!\n--CUSTOM--' "http://localhost:5001/api/v0/add"

L'idée de base est que chaque partie (divisée par chaîne dans boundary avec --) a ses propres en-têtes (Content-Type dans la deuxième partie, par exemple). Le FormData object gère tout cela pour vous, c'est donc un meilleur moyen d'atteindre nos objectifs.

Cela se traduit par récupérer l'API comme ceci:

const formData = new FormData()
formData.append('blob', new Blob(['Hello World!\n']), 'test')

fetch('http://localhost:5001/api/v0/add', {
  method: 'POST',
  body: formData
})
.then(r => r.json())
.then(data => {
  console.log(data)
})
14
konsumer