【问题标题】:axios post request to send form dataaxios post请求发送表单数据
【发布时间】:2020-06-05 13:03:33
【问题描述】:

axios POST 请求正在访问控制器上的 url,但将 null 值设置为我的 POJO 类,当我在 chrome 中浏览开发人员工具时,有效负载包含数据。我做错了什么?

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

请求抛出错误

发布多部分/表单数据时出错。 Content-Type 标头缺少边界

如果我在邮递员中发出相同的请求,它工作正常并将值设置为我的 POJO 类。

谁能解释一下如何设置边界或如何使用 axios 发送表单数据。

【问题讨论】:

    标签: reactjs react-redux axios ajaxform axios-cookiejar-support


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      我在使用 FormData 和 axios 来调用 https://apps.dev.microsoft.com 服务时遇到了类似的问题,并且由于“请求正文必须包含以下参数:'grant_type '"

      重新格式化数据后

      {
        grant_type: 'client_credentials',
        id: '123',
        secret: '456789'
      }
      

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

      【讨论】:

      • 你救了我!出于某种原因,使用FormData 构建对象不起作用,但是当我按照您的建议执行data: 'grant_type=client_credentials&id=123&secret=456789', 之类的操作时,它就成功了!
      【解决方案3】:
       transformRequest: [
        function(data, headers) {
          headers["Content-Type"] = "application/json";
          return JSON.stringify(data);
        }
      ]
      

      试试这个,效果很好

      【讨论】:

        【解决方案4】:

        我需要使用 axios 一次上传多个文件,但由于 FormData API 的原因,我挣扎了一段时间:

        // const instance = axios.create(config);
        
        let fd = new FormData();
        for (const img of images) { // images is an array of File Object
          fd.append('images', img, img.name); // multiple upload
        }
        
        const response = await instance({
          method: 'post',
          url: '/upload/',
          data: fd
        })
        

        我没有指定 content-type: multipart/form-data 标头!

        【讨论】:

          【解决方案5】:

          https://www.npmjs.com/package/axios

          它的工作原理

          // "content-type": "application/x-www-form-urlencoded", // 提交这个

          import axios from 'axios';
          
          let requestData = {
                username : "abc@gmail.cm",
                password: "123456"
              };
             
              const url = "Your Url Paste Here";
          
              let options = {
                method: "POST",
                headers: { 
                  'Content-type': 'application/json; charset=UTF-8',
          
                  Authorization: 'Bearer ' + "your token Paste Here",
                },
                data: JSON.stringify(requestData),
                url
              };
              axios(options)
                .then(response => {
                  console.log("K_____ res :- ", response);
                  console.log("K_____ res status:- ", response.status);
                })
                .catch(error => {
                  console.log("K_____ error :- ", error);
                });
          

          获取请求

          fetch(url, {
              method: 'POST',
              body: JSON.stringify(requestPayload),           
              headers: {
                  'Content-type': 'application/json; charset=UTF-8',
                  Authorization: 'Bearer ' + token,
              },
          })
              // .then((response) => response.json()) .  // commit out this part if response body is empty
              .then((json) => {
                  console.log("response :- ", json);
              }).catch((error)=>{
                  console.log("Api call error ", error.message);
                  alert(error.message);
          });
          

          【讨论】:

            【解决方案6】:

            您可以使用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 问题:

            Can't get a .post with 'Content-Type': 'multipart/form-data' to work @ axios/axios

            【讨论】:

            • bodyFormData.set 不是函数我收到此错误
            • 你需要使用append而不是set。
            • @ManojBhardwaj 您需要绑定该函数,假设您在提交函数中发出请求,您需要绑定该函数。 ex:- onSubmit={this.submit(bind(this)} 或 ex:- 在构造函数中 constructor(super){ this.submit = this.submit.bind(this); } submit(){ axios({}) ;... }
            • 您的配置对象错误。应该是:{ method: 'post', url: 'myurl', data: bodyFormData, headers: {'Content-Type': 'multipart/form-data' } }
            • 在nodejs中你需要npm install --save form-data
            【解决方案7】:

            我还需要计算内容长度

            const formHeaders = form.getHeaders();
            formHeaders["Content-Length"] = form.getLengthSync()
            
            const config = {headers: formHeaders}
            
            return axios.post(url, form, config)
            .then(res => {
                console.log(`form uploaded`)
            })
            

            【讨论】:

            • 没有这个我无法得到回应。谢谢
            【解决方案8】:

            在我的例子中,问题在于 FormData 附加操作的格式需要填写额外的“选项”参数来定义文件名:

            var formData = new FormData();
            formData.append(fieldName, fileBuffer, {filename: originalName});
            

            我看到很多抱怨 axios 坏了,但实际上根本原因是没有正确使用表单数据。我的版本是:

            "axios": "^0.21.1",
            "form-data": "^3.0.0",
            

            在接收端,我正在使用 multer 处理这个问题,最初的问题是文件数组没有被填充 - 我总是收到一个请求,但没有从流中解析出任何文件。

            另外,需要在axios请求中传递form-data头设置:

                    const response = await axios.post(getBackendURL() + '/api/Documents/' + userId + '/createDocument', formData, {
                    headers: formData.getHeaders()
                });
            

            我的整个函数如下所示:

            async function uploadDocumentTransaction(userId, fileBuffer, fieldName, originalName) {
                var formData = new FormData();
                formData.append(fieldName, fileBuffer, {filename: originalName});
            
                try {
                    const response = await axios.post(
                        getBackendURL() + '/api/Documents/' + userId + '/createDocument',
                        formData,
                        {
                            headers: formData.getHeaders()
                        }
                    );
            
                    return response;
                } catch (err) {
                    // error handling
                }
            }
            

            “fieldName”的值并不重要,除非您有一些需要它的接收端处理。

            【讨论】:

            • 浏览器 formData 对象呢? Axios 不能很好地与浏览器表单数据一起使用
            【解决方案9】:

            就我而言,我必须将 boundary 添加到 header 中,如下所示:

            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,此解决方案也很有用。

            【讨论】:

            • 这解决了我在尝试发布到 imgur 的 api 时遇到的问题。文档中没有提到任何地方,但没有它,您会收到 400 Invalid URL 响应。
            • FormData._boundary 在 Chrome 76 和 Firefox 67 和 axios deletes the Content-Type header anyway 中都未定义,所以这应该没有效果。
            • 边界部分是我的代码中唯一缺少的部分,在节点中完美运行!
            • 嗨,一个问题,虽然这仅适用于 android,但您是否设法使其在 iOS 设备上运行?
            • @KevinRED 是的,当时我实际上正在将 React Native 与 iOS 应用程序一起使用......
            【解决方案10】:

            上传(多个)二进制文件

            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: {'Content-Type': 'multipart/form-data' } 我更喜欢headers: formData.getHeaders()
            • 我使用上面的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)
            

            【讨论】:

            • 非常感谢这个例子,很难弄清楚为什么多个文件上传不起作用。
            • 我不是专家,但就我而言,我已经设法避免了使用for(var x = 0; x&lt;this.state.files.length; x++) { formData.append('files[]', this.state.files[x]) } 进行多文件上传的这些并发症(concat-streamasyncawait)所以我可以使用axios.post(url, formData, config) 提交
            • @laimison 谢谢,它对我有用。我已经更新了我的答案。
            • @TylerLong 我在 FormData API 中找不到任何 getHeaders 方法。 developer.mozilla.org/en-US/docs/Web/API/FormData
            • headers: formData.getHeaders() 是它为我工作的原因。谢谢。
            【解决方案11】:
            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);
                  });
              };
            

            【讨论】:

              【解决方案12】:

              2020 ES6 做事方式

              在 html 中使用表单我绑定到数据中,如下所示:

              数据:

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

              提交:

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

              【讨论】:

                【解决方案13】:

                上述方法对我有用,但由于它是我经常需要的东西,所以我使用了平面对象的基本方法。注意,我也在使用 Vue 而不是 REACT

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

                这对我有用,直到我遇到带有嵌套对象和文件的更复杂的数据结构,然后让以下内容进入

                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 未定义,formData 在 for 外部返回,但在 for 内部定义。 formData 很简单,但 objectToFormData 应该是什么?
                • 我认为它应该是函数的名称。因为它是递归的,所以我假设您可以将objectToFormData 更改为packageData,反之亦然
                【解决方案14】:

                更直接:

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

                【讨论】:

                • 是的,看起来,如果没有文件上传,这是最简单的方法。
                【解决方案15】:

                查看querystring

                您可以按如下方式使用它:

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

                【讨论】:

                • 这在节点环境下会更好
                • 如果您的数据中有嵌套对象,“querystring”可能无法按预期工作。在这种情况下,您可以使用“qs”模块对数据进行字符串化。
                • 这不是表单数据。这是一种 url 编码的表单格式。
                • 查询字符串包由于某种原因已被弃用
                猜你喜欢
                • 2021-05-07
                • 2021-10-21
                • 1970-01-01
                • 1970-01-01
                • 2019-11-24
                • 2019-02-25
                • 2021-06-08
                • 2019-02-02
                相关资源
                最近更新 更多