axios的post请求传参问题与post的四种编码方式

2019-03-01  本文已影响0人  MarkOut

尝试了一下Express中的post请求,原以为和get请求是一样的。

axios的post请求的官方示例是这样的:

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

但是结果发现,在后端无论如何都没有返回我需要的数据。

原来,POST方法提交的数据有四种编码方式。

1.application/x-www-form-urlencoded

这种方式是最常见的POST编码方式。浏览器的原生<form>表单,如果不设置enctype属性,那么最终就会以 application/x-www-form-urlencoded方式提交数据。

很多时候,我们用 Ajax 提交数据时,也是使用这种方式。例如 JQueryQWrap 的 Ajax,Content-Type 默认值都是「application/x-www-form-urlencoded;charset=utf-8」。

  1. multipart/form-data

我们使用表单上传文件时,必须让 <form> 表单的 enctype 等于 multipart/form-data。

这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。

上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,而且现阶段标准中原生 <form> 表单也只支持这两种方式(通过 <form> 元素的 enctype 属性指定,默认为 application/x-www-form-urlencoded。其实 enctype 还支持 text/plain,不过用得非常少)。

随着越来越多的 Web 站点,尤其是 WebApp,全部使用 Ajax 进行数据交互之后,我们完全可以定义新的数据提交方式,给开发带来更多便利。

3 .application/json

现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。

4.text/xml

它是一种使用 HTTP 作为传输协议,XML 作为编码方式的远程调用规范。XML-RPC 协议简单、功能够用,各种语言的实现都有。它的使用也很广泛,如 WordPress 的 XML-RPC Api,搜索引擎的 ping 服务等等。JavaScript 中,也有现成的库支持以这种方式进行数据交互,能很好的支持已有的 XML-RPC 服务。

相比之下,get方式的数据提交方式(编码方式)只有一种,就是application/x-www-form-urlencoding

我们的axios用的就是第三种编码方式,也就是application/json,但是Express的post默认是第一种方式,所以我们就找不到我们要的数据了。

问题找到了,就要想办法解决问题。既然是前后端的数据编码方式不一样,那么只要想办法让他们一样就行了。

首先,把后端的接收格式改成application/json。在Express中,我们需要用到一个叫做bodyParser的中间件。

引入body-parser:

$ npm install body-parser --save

基本使用:

var express = require('express')
//获取模块
var bodyParser = require('body-parser')

var app = express()

// 创建 application/json 解析
var jsonParser = bodyParser.json()

// 创建 application/x-www-form-urlencoded 解析
var urlencodedParser = bodyParser.urlencoded({ extended: false })

// POST /login 获取 URL编码的请求体
app.post('/login', urlencodedParser, function (req, res) {
  if (!req.body) return res.sendStatus(400)
  res.send('welcome, ' + req.body.username)
})

// POST /api/users 获取 JSON 编码的请求体
app.post('/api/users', jsonParser, function (req, res) {
  if (!req.body) return res.sendStatus(400)
  // create user in req.body
});
app.listen(3000);

对请求体的四种解析方式:

1. bodyParser.json(options): 解析json数据
2. bodyParser.raw(options): 解析二进制格式(Buffer流数据)
3. bodyParser.text(options): 解析文本数据
4. bodyParser.urlencoded(options): 解析UTF-8的编码的数据。

最后,bodyParser变量是对中间件的引用。请求体解析后,解析值都会被放到req.body属性,所以直接拿出来就行了。

有的时候后端已经固定了,没有办法只能改前端。

前端:

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

参考文献:
浏览器行为:Form表单提交
post提交数据的四种编码方式
Express 中间件----body-parser(五)

上一篇下一篇

猜你喜欢

热点阅读