Axios发送POST请求以发送表单数据

445

当我使用axios POST请求控制器的网址时,它会将空值设置为我的POJO类,但是当我通过谷歌开发者工具查看有效负载时,它包含数据。我做错了什么?

Axios POST请求:

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

浏览器响应:

在此输入图片描述

如果我设置以下标头:

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

请求发生错误

提交multipart/form-data时出错。缺少Content-Type头信息的boundary属性

如果我在postman中发送相同的请求,一切都很正常,并且将值设置到我的POJO类中。

有人可以解释一下如何设置boundary或者如何使用axios发送表单数据吗?


这与React和Redux有什么关系?我们能不能只用通用的JS来实现? - ggorlen
20个回答

686

您可以使用FormData()来发布axios数据,例如:

var bodyFormData = new FormData();

然后将这些字段添加到您要发送的表单中:

bodyFormData.append('userName', 'Fred');
如果您要上传图像,您可能希望使用.append
bodyFormData.append('image', imageFile); 

然后你可以使用axios的post方法(你可以根据需要进行修改)

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

相关的 GitHub 问题:

无法在 axios/axios 上使用 'Content-Type': 'multipart/form-data' 进行 .post


9
bodyFormData.set不是一个函数,我收到了这个错误。 - Manoj Bhardwaj
20
请使用 "append" 而不是 "set"。 - Pratik Singhal
4
您的配置对象有误,应该为: { method: 'post', url: 'myurl', data: bodyFormData, headers: {'Content-Type': 'multipart/form-data'} } - Steve Taylor
7
在Node.js中,您需要运行npm install --save form-data - bvdb
1
最新版的 axios 自动设置了 boundary 的 Content-Type 标头,所以最好不要更改它。 - user1338062
显示剩余8条评论

96

在我的情况下,我不得不像以下这样向

添加boundary

const form = new FormData();
form.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}`,
    },
});

如果您正在使用React Native,此解决方案也非常有用。


6
尝试上传图片到imgur的api时,我遇到了问题。文档中没有提到,但如果没有使用它,你将会得到400无效URL响应。 - Kolby
13
在Chrome 76和Firefox 67中,FormData._boundary未定义,并且axios无论如何都会删除Content-Type标头,因此这应该没有影响。 - ash
3
边界部分是我代码中唯一缺失的部分,在Node中完美运行! - Rafael Moni
1
@KevinRED 是的,当时我实际上正在使用React Native开发iOS应用程序... - Luiz Dias
1
"_boundary" 只存在于 form-data 的 npm 模块中,而不是浏览器原生的 FormData!你应该使用 getBoundary() 或更好的 getHeaders()。在浏览器中,你只需要设置 'Content-Type': 'multipart/form-data' 而不需要 boundary。 - Dantio
显示剩余6条评论

53

查看querystring

你可以按照以下方式使用它:

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

4
在Node环境下,这会更好。 - Jjagwe Dennis
如果您的数据中有嵌套对象,则“querystring”可能无法按预期工作。在这种情况下,您可以使用“qs”模块对数据进行字符串化。 - Zihad Ul Islam
11
这不是表单数据,而是一种经过URL编码的表单格式。 - ancyrweb
查询字符串包由于某些原因已被弃用。 - Jon Onstott
Querystring已经被弃用。现在的方法是:const data = new URLSearchParams(dataObject).toString(); 然后提交该数据对象。 - Andrew Taylor

37

上传(多个)二进制文件

Node.js

如果您想通过 multipart/form-data 方式提交文件,特别是多个二进制文件,事情就变得复杂了。以下是一个可用的示例:

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()
})
  • 我更喜欢使用 headers: formData.getHeaders(),而不是 headers: {'Content-Type': 'multipart/form-data' }
  • 如果您不喜欢 asyncawait,可以将它们改成普通的 Promise 语句
  • 要添加自己的标头,只需使用如下代码: headers: { ...yourHeaders, ...formData.getHeaders() }

以下为新增内容:

浏览器

浏览器中的 FormData 与 NPM 包 'form-data' 不同。以下代码适用于浏览器:

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)

2
非常感谢您提供的示例,让我终于解决了多文件上传不起作用的问题。 - Minkesh Jain
2
我不是专家,但在我的情况下,我成功地避免了使用 concat-streamasyncawait 来进行多文件上传的复杂性。我使用 for(var x = 0; x<this.state.files.length; x++) { formData.append('files[]', this.state.files[x]) },这样我就可以使用 axios.post(url, formData, config) 进行提交。 - laimison
1
@laimison 谢谢,这对我有用。我已经更新了我的答案。 - Tyler Liu
当您有二进制文件时,在Node.js端使用mutler时,此方法无法正常工作。 - Игор Ташевски
@ИгорТашевски 请向 multer 项目报告此问题。 - Tyler Liu
显示剩余4条评论

18

2020 ES6的方法

在html中有一个表单,我将数据绑定如下:

数据:

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

18

在axios中使用application/x-www-form-urlencoded格式

默认情况下,axios将JavaScript对象序列化为JSON。如果要发送application/x-www-form-urlencoded格式的数据,可以使用以下选项之一。

浏览器

在浏览器中,您可以使用URLSearchParams API,如下所示:

const params = new URLSearchParams();

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

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

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

请注意,不是所有浏览器都支持URLSearchParams(请参见caniuse.com),但是有一个polyfill可用(确保对全局环境进行polyfill)。

或者,您可以使用qs库对数据进行编码:

const qs = require('qs');

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

或者另一种方式(ES6),

import qs from 'qs';

const data = { 'bar': 123 };

const options = {

  method: 'POST',

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

  data: qs.stringify(data),

  url, };

axios(options);

8

2022年的方式

Axios文档尚未更新,但现在有一种便捷的方法来创建formdata,可以使用axios.toFormData()方法。

以下是它的TypeScript定义:

export function toFormData(sourceObj: object, targetFormData?: GenericFormData, options?: FormSerializerOptions): GenericFormData;

例子:

const formData = axios.toFormData({"myField":"myValue"})

const response = await axios({
  method: "post",
  url: "...",
  data: formData,
  headers: { ... }
})

来源:

您可以在 Axios 的变更日志中找到以下内容

[1.0.0] - 2022-10-04

为暴露的 toFormData 助手添加了通用的 TS 类型 #4668

添加了增强的 toFormData 实现,包含额外选项 4704


1
请注意,布尔值和数字必须被编码为字符串。 例如,axios.toFormData({"foo": true})会抛出TypeError: data should be a string, Buffer or Uint8Array的错误。请改用axios.toFormData({"foo": "true"}) - AnonBird

6
当我使用axios和FormData在https://apps.dev.microsoft.com服务上进行调用时,出现了类似的问题,并且它会出现错误提示 "The request body must contain the following parameter: 'grant_type'"。
重新格式化数据后,问题得到了解决。
{
  grant_type: 'client_credentials',
  id: '123',
  secret: '456789'
}

to

"grant_type=client_credentials&id=123&secret=456789"

以下代码运行成功:
const config: AxiosRequestConfig = {
    method: 'post',
    url: https://apps.dev.microsoft.com/auth,
    data: 'grant_type=client_credentials&id=123&secret=456789',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
    }
};

axios(config)
.then(function (response) {
  console.log(JSON.stringify(response.data));
})
.catch(function (error) {
  console.log(error);
});

3
你救了我!不知何故,使用 FormData 构建对象无效,但是当我按照你的建议使用 data: 'grant_type=client_credentials&id=123&secret=456789' 这样的方式时,就成功了! - thodwris
我必须说,这确实起作用了!Postman可以使用formdata,但在我的项目中却不行。+1 - Craws

6
更加简单明了:

更加直白:

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

9
是的,看起来如果没有文件上传,这是最简单的方法。 - Akalanka Weerasooriya

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接