buscar publicación con datos de formulario de varias partes

86

Estoy obteniendo una URL como esta:

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

Mi API espera que los datos sean de, multipart/form-datapor lo que estoy usando content-typeeste tipo ... Pero me está dando una respuesta con el código de estado 400.

¿Qué pasa con mi código?

ario
fuente

Respuestas:

163

Está configurando el Content-Typeto be multipart/form-data, pero luego usa JSON.stringifyen los datos del cuerpo, que devuelve application/json. Tiene una discrepancia en el tipo de contenido.

Deberá codificar sus datos como en multipart/form-datalugar de json. Por multipart/form-datalo general, se usa al cargar archivos y es un poco más complicado que application/x-www-form-urlencoded(que es el predeterminado para los formularios HTML).

La especificación de multipart/form-datase puede encontrar en RFC 1867 .

Para obtener una guía sobre cómo enviar ese tipo de datos a través de javascript, consulte aquí .

La idea básica es utilizar el objeto FormData (no compatible con 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
  });

  // ...
}

Según este artículo, asegúrese de no configurar el Content-Typeencabezado. El navegador lo configurará por usted, incluido el boundaryparámetro.

rossipedia
fuente
const fd = new FormData (); // Subir Archivo. fd.append ('archivo', fileToUpload); fd.append ('jsondatakey', 'jsondatavalue'); Con esto, podrá enviar un archivo junto con algunos datos json en el cuerpo.
Jnana
25

Recientemente estuve trabajando con IPFS y resolví esto. Un ejemplo de curl para que IPFS cargue un archivo se ve así:

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"

La idea básica es que cada parte (dividida por cadena boundarycon --) tiene sus propios encabezados ( Content-Typeen la segunda parte, por ejemplo). El FormDataobjeto gestiona todo esto por ti, por lo que es una mejor manera de lograr nuestros objetivos.

Esto se traduce en buscar API como esta:

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
fuente
16
Tenga en cuenta sobre el método anterior, NO proporcione encabezados si lo hace usando FormData porque anulará el límite que se establece automáticamente.
Matt Pengelly
1
¡Gracias @MattPengelly! ¿Cómo configurar encabezados personalizados como Autorización entonces?
Dragos Strugar
7
@DragosStrugar aún puede establecer encabezados (autorización incluida), simplemente no configure manualmente el encabezado de tipo de contenido si está utilizando FormData.
RobertMcReed
2
NO proporcione encabezados con 'Content-Type' si está usando FormData.
2019
1
En el ejemplo de rizo, lo necesitas. En el FormDataejemplo, no lo necesita, porque el navegador envía ese encabezado por usted y también administra todos los límites de mímica, que es el objetivo de esta solución.
konsumer