Axios post solicitud para enviar datos del formulario


204

La POSTsolicitud de axios está llegando a la url en el controlador pero estableciendo valores nulos para mi clase POJO, cuando reviso las herramientas de desarrollador en Chrome, la carga útil contiene datos. ¿Qué estoy haciendo mal?

Solicitud POST de Axios:

var body = {
    userName: 'Fred',
    userEmail: 'Flintstone@gmail.com'
}

axios({
    method: 'post',
    url: '/addUser',
    data: body
})
.then(function (response) {
    console.log(response);
})
.catch(function (error) {
    console.log(error);
});

Respuesta del navegador:

ingrese la descripción de la imagen aquí

Si configuro encabezados como:

headers:{
  Content-Type:'multipart/form-data'
}

La solicitud arroja el error

Error al publicar datos multiparte / formulario. Al encabezado de tipo de contenido le falta el límite

Si hago la misma solicitud en cartero, está funcionando bien y establece valores para mi clase POJO.

¿Alguien puede explicar cómo establecer límites o cómo puedo enviar datos de formulario usando axios?

Respuestas:


328

Puede publicar datos de axios utilizando FormData () como:

var bodyFormData = new FormData();

Y luego agregue los campos al formulario que desea enviar:

bodyFormData.set('userName', 'Fred');

Si está cargando imágenes, puede usar .append

bodyFormData.append('image', imageFile); 

Y luego puede usar el método de publicación axios (puede modificarlo en consecuencia)

axios({
    method: 'post',
    url: 'myurl',
    data: bodyFormData,
    headers: {'Content-Type': 'multipart/form-data' }
    })
    .then(function (response) {
        //handle success
        console.log(response);
    })
    .catch(function (response) {
        //handle error
        console.log(response);
    });

Puedes leer más aquí


8
bodyFormData.set no es una función, recibí este error
Manoj Bhardwaj

10
Debe usar append en lugar de set.
Pratik Singhal

1
@ManojBhardwaj necesita vincular la función, suponga que si realiza una solicitud dentro de la función de envío debe vincular esa función. ex: - onSubmit = {this.submit (bind (this)} o ex: - en el constructor constructor (super) {this.submit = this.submit.bind (this);} submit () {axios ({}) ; ...}
Srikanth Gowda

bodyFormData.append también me funcionó. no estoy seguro de por qué setno funciona
Im Batman

1
Su objeto de configuración está mal. Debería ser:{ method: 'post', url: 'myurl', data: bodyFormData, headers: {'Content-Type': 'multipart/form-data' } }
Steve Taylor

35

Echa un vistazo a la cadena de consulta .

Puede usarlo de la siguiente manera:

var querystring = require('querystring');
axios.post('http://something.com/', querystring.stringify({ foo: 'bar' }));

44
Esto es aún mejor en un entorno de nodo
Jjagwe Dennis,

Si tiene objetos anidados en sus datos, 'querystring' puede no funcionar como se esperaba. En ese caso, puede usar el módulo 'qs' para stringificar los datos.
Zihad Ul Islam

33

En mi caso, tuve que agregar el límite al encabezado de la siguiente manera:

const form = new FormData();
    formData.append(item.name, fs.createReadStream(pathToFile));

    const response = await axios({
        method: 'post',
        url: 'http://www.yourserver.com/upload',
        data: form,
        headers: {
        'content-type': `multipart/form-data; boundary=${form._boundary}`,
        },
    });

Esta solución también es útil si está trabajando con React Native.


3
Esto resolvió mi problema al intentar publicar en la api de imgur. No se menciona en ninguna parte de los documentos, pero sin ella obtienes una respuesta de 400 URL no válidas.
Kolby

1
FormData._boundaryno está definido tanto en Chrome 76 como en Firefox 67, y axios elimina el encabezado Content-Type de todos modos , por lo que esto no debería tener ningún efecto.
Ash

1
¡La parte límite era lo único que faltaba en mi código, funcionaba perfectamente en el nodo!
Rafael Moni

eres un salvador de vida
Kevin RED

Hola, un problema, aunque esto solo funciona en Android, ¿lograste que funcione en dispositivos iOS?
Kevin RED

15

Subir (múltiples) archivos binarios

Node.js

Las cosas se complican cuando quieres publicar archivos a través de multipart/form-data, especialmente múltiples archivos binarios. A continuación se muestra un ejemplo de trabajo:

const FormData = require('form-data')
const fs = require('fs')
const path = require('path')

const formData = new FormData()
formData.append('files[]', JSON.stringify({ to: [{ phoneNumber: process.env.RINGCENTRAL_RECEIVER }] }), 'test.json')
formData.append('files[]', fs.createReadStream(path.join(__dirname, 'test.png')), 'test.png')
await rc.post('/restapi/v1.0/account/~/extension/~/fax', formData, {
  headers: formData.getHeaders()
})
  • En lugar de headers: {'Content-Type': 'multipart/form-data' }prefieroheaders: formData.getHeaders()
  • Utilizo asyncy más awaitarriba, puede cambiarlos a declaraciones simples de Promesa si no le gustan

Contenido recientemente agregado a continuación:

Navegador

El navegador FormDataes diferente del paquete NPM 'form-data'. El siguiente código me funciona en el navegador:

HTML:

<input type="file" id="image" accept="image/png"/>

JavaScript:

const formData = new FormData()

// add a non-binary file
formData.append('files[]', new Blob(['{"hello": "world"}'], { type: 'application/json' }), 'request.json')

// add a binary file
const element = document.getElementById('image')
const file = element.files[0]
formData.append('files[]', file, file.name)
await rc.post('/restapi/v1.0/account/~/extension/~/fax', formData)

1
Muchas gracias por este ejemplo, me costó descubrir por qué la carga de varios archivos no funcionaba.
Minkesh Jain

1
No soy un experto, pero en mi caso he logrado evitar estas complicaciones ( concat-stream, asyncy await) para la carga de archivos múltiples utilizando for(var x = 0; x<this.state.files.length; x++) { formData.append('files[]', this.state.files[x]) }para que pueda presentar utilizandoaxios.post(url, formData, config)
laimison

@laimison gracias, funciona para mí. He actualizado mi respuesta.
Tyler Long

@ TylerLong No puedo encontrar ningún método getHeaders en FormData API. developer.mozilla.org/en-US/docs/Web/API/FormData
ankur_rajput

9

Aún más directo:

axios.post('/addUser',{
    userName: 'Fred',
    userEmail: 'Flintstone@gmail.com'
})
.then(function (response) {
    console.log(response);
})
.catch(function (error) {
    console.log(error);
});

2
Sí, como parece, si no hay cargas de archivos, esta es la forma más fácil.
Akalanka Weerasooriya

3

Uso del formato application / x-www-form-urlencoded en axios

Por defecto, axios serializa objetos JavaScript a JSON. Para enviar datos en el formato application / x-www-form-urlencoded, puede utilizar una de las siguientes opciones.

Navegador

En un navegador, puede usar la API URLSearchParams de la siguiente manera:

const params = new URLSearchParams ();

params.append ('param1', 'value1');

params.append ('param2', 'value2');

axios.post ('/ foo', params);

Tenga en cuenta que URLSearchParams no es compatible con todos los navegadores (consulte caniuse.com), pero hay un polyfill disponible (asegúrese de polyfill el entorno global).

Alternativamente, puede codificar datos usando la biblioteca qs:

const qs = require ('qs');

axios.post ('/ foo', qs.stringify ({'bar': 123}));

O de otra manera (ES6),

importar qs desde 'qs';

const data = {'bar': 123};

opciones de const = {

método: 'POST',

encabezados: {'content-type': 'application / x-www-form-urlencoded'},

datos: qs.stringify (datos),

url};

axios (opciones);


3

2020 ES6 forma de hacer

Teniendo el formulario en html, vinculé datos como este:

DATOS:

form: {
   name: 'Joan Cap de porc',
   email: 'fake@email.com',
   phone: 2323,
   query: 'cap d\ou'
   file: null,
   legal: false
},

onSubmit:

async submitForm() {
  const formData = new FormData()
  Object.keys(this.form).forEach((key) => {
    formData.append(key, this.form[key])
  })

  try {
    await this.$axios.post('/ajax/contact/contact-us', formData)
    this.$emit('formSent')
  } catch (err) {
    this.errors.push('form_error')
  }
}

1

El método anterior funcionó para mí, pero como era algo que necesitaba con frecuencia, utilicé un método básico para objetos planos. Tenga en cuenta que también estaba usando Vue y no REACT

packageData: (data) => {
  const form = new FormData()
  for ( const key in data ) {
    form.append(key, data[key]);
  }
  return form
}

Lo que funcionó para mí hasta que me encontré con estructuras de datos más complejas con objetos anidados y archivos que luego permitieron lo siguiente

packageData: (obj, form, namespace) => {
  for(const property in obj) {
    // if form is passed in through recursion assign otherwise create new
    const formData = form || new FormData()
    let formKey

    if(obj.hasOwnProperty(property)) {
      if(namespace) {
        formKey = namespace + '[' + property + ']';
      } else {
        formKey = property;
      }

      // if the property is an object, but not a File, use recursion.
      if(typeof obj[property] === 'object' && !(obj[property] instanceof File)) {
        packageData(obj[property], formData, property);
      } else {
        // if it's a string or a File
      formData.append(formKey, obj[property]);
      }
    }
  }
  return formData;
}

objectToFormData no está definido y formData se devuelve fuera de for, pero se define dentro de for. formData es fácil, pero ¿qué se supone que debe ser objectToFormData?
Trevor

Creo que se supone que es el nombre de la función. ya que está destinado a ser recursivo, así que supongo que se puede cambiar el objectToFormDataa packageDatao viceversa
Raymond Ativie

0
import axios from "axios";
import qs from "qs";   

const url = "https://yourapplicationbaseurl/api/user/authenticate";
    let data = {
      Email: "testuser@gmail.com",
      Password: "Admin@123"
    };
    let options = {
      method: "POST",
      headers: { "content-type": "application/x-www-form-urlencoded" },
      data: qs.stringify(data),
      url
    };
    axios(options)
      .then(res => {
        console.log("yeh we have", res.data);
      })
      .catch(er => {
        console.log("no data sorry ", er);
      });
  };
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.