buscar postagem com dados de formulário multipartes

86

Estou buscando um URL como este:

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

Minha API espera que os dados sejam de, multipart/form-dataentão estou usando content-typeesse tipo ... Mas está me dando uma resposta com o código de status 400.

O que há de errado com meu código?

ariano
fonte

Respostas:

163

Você está definindo o Content-Typepara ser multipart/form-data, mas depois usando JSON.stringifyos dados do corpo, que retornam application/json. Você tem uma incompatibilidade de tipo de conteúdo.

Você precisará codificar seus dados como em multipart/form-datavez de json. Normalmente multipart/form-dataé usado ao enviar arquivos e é um pouco mais complicado do que application/x-www-form-urlencoded(que é o padrão para formulários HTML).

A especificação para multipart/form-datapode ser encontrada no RFC 1867 .

Para obter um guia sobre como enviar esse tipo de dados via javascript, clique aqui .

A ideia básica é usar o objeto FormData (não compatível com 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
  });

  // ...
}

De acordo com este artigo, certifique-se de não definir o Content-Typecabeçalho. O navegador irá configurá-lo para você, incluindo o boundaryparâmetro.

Rossipedia
fonte
const fd = new FormData (); // Arquivo para upload. fd.append ('arquivo', arquivoToUpload); fd.append ('jsondatakey', 'jsondatavalue'); Com isso você poderá enviar o arquivo junto com alguns dados json no corpo.
Jnana
25

Recentemente, trabalhei com o IPFS e resolvi isso. Um exemplo curl de IPFS para fazer upload de um arquivo tem a seguinte aparência:

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"

A ideia básica é que cada parte (dividida por string boundarycom --) tenha seus próprios cabeçalhos ( Content-Typena segunda parte, por exemplo). O FormDataobjeto gerencia tudo isso para você, então é a melhor maneira de atingir nossos objetivos.

Isso se traduz em buscar API assim:

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
fonte
16
Nota sobre o método acima, NÃO forneça cabeçalhos se você fizer isso usando FormData porque ele irá substituir o limite que é definido automaticamente.
Matt Pengelly
1
Obrigado @MattPengelly! Então, como definir cabeçalhos personalizados como Autorização?
Dragos Strugar
7
@DragosStrugar você ainda pode definir cabeçalhos (autorização incluída), apenas não defina manualmente o cabeçalho Content-Type se estiver usando FormData.
RobertMcReed
2
NÃO forneça cabeçalhos com 'Content-Type' se estiver usando FormData.
caot de
1
No exemplo do curl, você precisa disso. No FormDataexemplo, você não precisa disso, porque o navegador envia esse cabeçalho para você e também gerencia todos os limites do mime, que é o ponto desta solução.
konsumer