Post mit mehrteiligen Formulardaten abrufen

85

Ich rufe eine URL wie folgt ab:

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

Meine API erwartet, dass die Daten von diesem Typ sind, multipart/form-dataalso verwende ich content-typediesen Typ ... Aber es gibt mir eine Antwort mit dem Statuscode 400.

Was ist los mit meinem Code?

arisch
quelle

Antworten:

162

Sie setzen das Content-Typeauf sein multipart/form-data, verwenden dann aber JSON.stringifydie Körperdaten, die zurückgegeben werden application/json. Sie haben eine Nichtübereinstimmung mit dem Inhaltstyp.

Sie müssen Ihre Daten als multipart/form-datastatt verschlüsseln json. Wird normalerweise multipart/form-databeim Hochladen von Dateien verwendet und ist etwas komplizierter als application/x-www-form-urlencoded(dies ist die Standardeinstellung für HTML-Formulare).

Die Spezifikation für multipart/form-datafinden Sie in RFC 1867 .

Eine Anleitung zum Übermitteln dieser Art von Daten über Javascript finden Sie hier .

Die Grundidee besteht darin, das FormData- Objekt zu verwenden (in IE <10 nicht unterstützt):

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

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

  const response = await fetch(url, {
    method: 'POST',
    body: formData
  });

  // ...
}

Stellen Sie gemäß diesem Artikel sicher, dass der Header nicht festgelegt wird Content-Type. Der Browser legt es für Sie fest, einschließlich des boundaryParameters.

rossipedia
quelle
const fd = new FormData (); // Datei zum Hochladen. fd.append ('file', fileToUpload); fd.append ('jsondatakey', 'jsondatavalue'); Mit dieser Option können Sie Dateien zusammen mit einigen JSON-Daten im Body senden.
Jnana
25

Ich habe kürzlich mit IPFS gearbeitet und das herausgefunden. Ein Curl-Beispiel für das Hochladen einer Datei durch IPFS sieht folgendermaßen aus:

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"

Die Grundidee ist, dass jeder Teil (aufgeteilt durch Zeichenfolge in boundarymit --) seine eigenen Überschriften hat ( Content-Typezum Beispiel im zweiten Teil). Das FormDataObjekt verwaltet dies alles für Sie, sodass es eine bessere Möglichkeit ist, unsere Ziele zu erreichen.

Dies bedeutet, dass die API wie folgt abgerufen wird:

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)
})
konsumer
quelle
16
Hinweis zur obigen Methode: Geben Sie KEINE Header an, wenn Sie FormData verwenden, da dadurch die automatisch festgelegte Grenze überschrieben wird.
Matt Pengelly
1
Danke @MattPengelly! Wie setze ich dann benutzerdefinierte Header wie Authorization?
Dragos Strugar
7
@DragosStrugar Sie können weiterhin Header festlegen (Autorisierung eingeschlossen). Legen Sie den Content-Type-Header nur nicht manuell fest, wenn Sie FormData verwenden.
RobertMcReed
2
Geben Sie KEINE Header mit 'Content-Type' an, wenn FormData verwendet wird.
Caot
1
Im Curl-Beispiel brauchen Sie es. In dem FormDataBeispiel brauchen Sie es nicht, weil der Browser diesen Header für Sie sendet und auch alle MIME-Grenzen verwaltet, worum es bei dieser Lösung geht.
Konsumer