Come faccio a POST con i dati di un modulo multiparte utilizzando il recupero?


90

Sto recuperando un URL come questo:

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

La mia API si aspetta che i dati siano multipart/form-datacosì che sto usando content-typedi questo tipo ... Ma mi sta dando una risposta con codice di stato 400.

Cosa c'è di sbagliato nel mio codice?

Risposte:


176

Stai impostando l' Content-Typeessere multipart/form-data, ma poi usi JSON.stringifysui dati del corpo, che ritorna application/json. Hai una mancata corrispondenza del tipo di contenuto.

Dovrai codificare i tuoi dati come multipart/form-datainvece di json. Di solito multipart/form-dataviene utilizzato durante il caricamento dei file ed è un po 'più complicato di application/x-www-form-urlencoded(che è l'impostazione predefinita per i moduli HTML).

La specifica per multipart/form-datapuò essere trovata in RFC 1867 .

Per una guida su come inviare questo tipo di dati tramite javascript, vedere qui .

L'idea di base è utilizzare l' oggetto FormData (non supportato in IE <10):

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

  // ...
}

Per questo articolo assicurati di non impostare l' Content-Typeintestazione. Il browser lo imposterà per te, incluso il boundaryparametro.


const fd = new FormData (); // File da caricare. fd.append ('file', fileToUpload); fd.append ('jsondatakey', 'jsondatavalue'); Con questo sarai in grado di inviare file insieme ad alcuni dati json nel corpo.
Jnana

E se ho bisogno di un'autorizzazione?
DAVE

26

Di recente stavo lavorando con IPFS e l'ho risolto. Un esempio di curl per IPFS per caricare un file è simile al seguente:

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'idea di base è che ogni parte (divisa per stringa in boundarycon --) ha le proprie intestazioni ( Content-Typenella seconda parte, ad esempio).FormData oggetto gestisce tutto questo per te, quindi è un modo migliore per raggiungere i nostri obiettivi.

Questo si traduce in recuperare API in questo modo:

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

17
Nota sul metodo sopra, NON fornire intestazioni se lo fai utilizzando FormData perché sovrascriverà il limite impostato automaticamente.
Matt Pengelly

1
Grazie @MattPengelly! Come impostare quindi intestazioni personalizzate come Autorizzazione?
Dragos Strugar

7
@DragosStrugar puoi ancora impostare le intestazioni (autorizzazione inclusa), ma non impostare manualmente l'intestazione Content-Type se stai usando FormData.
RobertMcReed

3
NON fornire intestazioni con "Content-Type" se utilizza FormData.
circa il

1
Nell'esempio del ricciolo, ne hai bisogno. Nel FormDataesempio, non è necessario, perché il browser invia tale intestazione per voi e gestisce anche tutti i MIME boundries, che è il punto di questa soluzione.
konsumer
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.