刚开始使用Vue,里面的坑是一个接一个,今天就遇到一个axios POST传参的问题。

因为后端要求是按表单提交的形式给他数据,

我需要在请求中传递参数,然后按官方文档的格式开始操作,代码如下:

axios.post('/user', {
 
    firstName: 'Fred',
 
    lastName: 'Flintstone'
 
  })
 
  .then(function (response) {
 
    console.log(response);
 
  })
 
  .catch(function (error) {
 
    console.log(error);
 
  });

注:此处是官方示例:点击打开链接

打开控制台,报400,报错信息是:传递的参数不存在,但在请求中看的到参数,只是参数的格式是Request Payload,具体也没看懂是什么,总之知道就是参数格式不对,查阅资料找到两种解决办法,代码如下:

1.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);
var params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);

参考:https://github.com/axios/axios#using-applicationx-www-form-urlencoded-format

经测试,这两种办法都可以

这个问题刚解决,后台就抛给我一个问题,我的参数里面要传数组呢,我以为直接按上面的做法就能一马平川了,然而现实是残酷的,崩盘!查看官方文档发现,其实这个的解决也是非常的简单,只需要在qs的方法中设置它的indices为false即可,如:

qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });

更多qs功能参考:https://www.npmjs.com/package/qs

vue框架推荐使用axios来发送ajax请求,之前我还写过一篇博客来讲解如何在vue组件中使用axios。但之前做着玩用的都是get请求,现在我自己搭博客时使用了post方法,结果发现后台(node.js)完全拿不到前台传来的参数。后来进过一番探索,终于发现问题所在。

post提交数据的四种编码方式

1.application/x-www-form-urlencoded 

这应该是最常见的post编码方式,一般的表单提交默认以此方式提交。大部分服务器语言对这种方式都有很好的支持。在PHP中,可以用$_POST[“key”]的方式获取到key的值,在node中我们可以使用querystring中间件对参数进行分离

app.post("/server",function(req,res){
    req.on("data",function(data){
        let key=querystring.parse(decodeURIComponent(data)).key;
        console.log("querystring:"+key)
    });
});

2.multipart/form-data
这也是一种比较常见的post数据格式,我们用表单上传文件时,必须使form表单的enctype属性或者ajax的contentType参数等于multipart/form-data。使用这种编码格式时发送到后台的数据长得像这样子

不同字段以–boundary开始,接着是内容描述信息,最后是字段具体内容。如果传输的是文件,还要包含文件名和文件类型信息

3.application/json
axios默认提交就是使用这种格式。如果使用这种编码方式,那么传递到后台的将是序列化后的json字符串。我们可以将application/json与application/x-www-form-urlencoded发送的数据进行比较
首先是application/json:

接着是application/x-www-form-urlencoded:

这里可以明显看出application/x-www-form-urlencoded上传到后台的数据是以key-value形式进行组织的,而application/json则直接是个json字符串。如果在处理application/json时后台还是采用对付application/x-www-form-urlencoded的方式将会产生问题。例如后台node.js依然采用之前对付application/x-www-form-urlencoded的方法,那么querystring.parse(decodeURIComponent(data))之后得到的数据是这样子的

这个时候再querystring.parse(decodeURIComponent(data)).key只能获取到undefined

4.text/xml
剩下的一种编码格式是text/xml,这种格式我没有怎么使用过

解决方法
既然我们知道axios post方法默认使用application/json格式编码数据,那么解决方案就有两种,一是后台改变接收参数的方法,另一种则是将axios post方法的编码格式修改为application/x-www-form-urlencoded,这样就不需要后台做什么修改了。
先来看第一种解决方法
vue组件中,axios发送post请求的代码如下

this.$axios({
    method:"post",
    url:"/api/haveUser",
    data:{
        name:this.name,
        password:this.password
    }
}).then((res)=>{
    console.log(res.data);
})

此时控制台Network Headers里面的信息是这样子的

后台接收数据需要依赖body-parser中间件,我们事先装好,接着在后台代码中引用body-parser

这张截图中,发挥作用的代码仅仅是const bodyParser=require(“body-parser”);
接下来在路由中使用body-parser

app.post("/api/haveUser",bodyParser.json(),function(req,res){
    console.log(req.body);
    let haveUser=require("../api/server/user.js");
    haveUser(req.body.name,req.body.password,res);
});

这时,当前台发送post请求之后,后台控制台中就会打印出req.body

这时,通过req.body.name或者req.body.password就能拿到对应的值。
这种方法比较简单,也不需要前台做过多修改,推荐使用这种方法。

第二种解决方法,具体操作如下
前端

this.$axios({
    method:"post",
    url:"/api/haveUser",
    headers:{
        'Content-type': 'application/x-www-form-urlencoded'
    },
    data:{
        name:this.name,
        password:this.password
    },
    transformRequest: [function (data) {
        let ret = ''
        for (let it in data) {
          ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
        }
        return ret
      }],
}).then((res)=>{
    console.log(res.data);
})

其中发挥关键作用的是headers与transformRequest。其中 headers 是设置即将被发送的自定义请求头。 transformRequest 允许在向服务器发送前,修改请求数据。这样操作之后,后台querystring.parse(decodeURIComponent(data))获取到的就是类似于{ name: ‘w’, password: ‘w’ }的对象。后台代码如下

app.post("/api/haveUser",function(req,res){
      let haveUser=require("../api/server/user.js");
      req.on("data",function(data){
          let name=querystring.parse(decodeURIComponent(data)).name;
          let password=querystring.parse(decodeURIComponent(data)).password;
          console.log(name,password)
          haveUser(name,password,res);
      });
});

这种方法明显就要比第一种麻烦一点,但不需要后台做过多处理。所以具体操作还是得根据实际情况决定。
————————————————
版权声明:本文为CSDN博主「哇偶哇偶Z」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ddwddw4/article/details/83624704

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐