使用axios发送post请求,传入了Object格式的参数,在node后端 req.body接收到的参数为空 ,但是网页上抓包检查时,发现请求的body确实是携带了参数的?
今天,我在写vue+node项目时,在提交 登录信息 (username,password)到后端时,就遇到了这个小bug,花了我一个半小时的时间,才搞出了个所以然来。
先介绍一下我后端node 使用到的包 :
"@escook/express-joi": "^1.1.1", //进行表单验证相关包
"cors": "^2.8.5", //解决请求跨域问题相关包
"express": "^4.17.2",//node.js的web应用框架
"joi": "^17.6.0", //定义表单验证规则的包
"mysql": "^2.18.1" //数据库相关包
app.js中部分基本配置:
// 配置解析 数据格式为表单数据的请求体 的中间件
app.use(express.urlencoded({ extended: false }))
// 导入 cors 中间件
const cors = require('cors')
// 将 cors 注册为全局中间件
app.use(cors())
后端使用了express搭建服务器,并使用了cors解决前端请求跨域问题,并配置了 joi的表单验证 ,每次向api提交的表单数据,都会先经过表单验证的中间件,其中验证规则设置了username和password都是required
前端vue组件中写的 登录请求函数 :

平平无奇的axios进行post提交表单的代码
于是我去页面进行了测试(Later....

我直接 蒟蒻问号 ???
显然,是我的表单验证 中间件没有拿到前端发送过去username信息 ,于是我开始了漫长的debug。
首先,我使用中间件,在数据提交到后台时,先在控制台打印一下req.body这个对象。

显而易见,服务器中 req.body请求体中没有任何参数 。但是页面确实是提交了数据呀?
于是我在页面F12进行网络抓包来查看发出去的request请求

抓到的包中请求体确实携带了页面发送的参数,然后我就开始意识到事情的不对劲了,开始在网上搜索答案。
后来,我把问题锁定到了axios请求机制和服务器对请求体数据解析上
之后尝试过在axios请求函数中,在header中配置内容数据格式为 'Content-Type': 'application/x-www-form-urlencoded ',依然没用
经过漫长的网上冲浪,并查了一下axios的源码,我发现
axios的文档上有这样一句话

这就能解释为什么我第一次发送的是obj对象数据,请求体携带的确是json格式的数据,说明axios会自动转换数据为json格式
后来我又在源码上看到了转换请求体参数格式的相关代码
if(utils.isURLSearchParams(data){
setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded');
return data.tostring();
}
if(utils.isObject(data){
setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
return JSON.stringfy(data);
}
显然,axios在发送请求时,如果参数对象data 不是表单数据格式对象 ,就会默认把数据 转为json字符串 ,放到请求体中的。
所以我之前发过去的obj对象,被axios自动转化为了json字符串
但是到此为止,感觉还是没有任何环节有致命问题呀?将JSON字符串格式的参数发给服务器,确实应该也没什么问题呀?
于是我就重新回到服务器的配置代码上来,显然,应该是服务器无法解析request请求的请求体body中JSON字符串的数据。
这让我想到了我最开始配置的这行代码
// 配置解析 数据格式为表单数据的请求体 的中间件
app.use(express.urlencoded({ extended: false }))
expres服务器默认无法解析数据格式为表单数据的请求体,因此express才提供了这个中间件,让我们配置,从而能够解析req.body 中表单格式数据。而这个中间件内部,其实是在配置body-parser属性,所以我的每个request请求都是要经过这个过滤器解析的,也就是说,这个 中间件不能解析json格式字符串 ????
经过网上查阅,我找到了如下解释
body-parser的urlencoded方法顾名思义就是 把传来的数据当做url来处理 ,也就是像querystring一样,所以对于传过来的json数据, 没有识别到切割key和value的标志 ,就把所有都当做key来处理
真相大白。body-parser无法解析请求体中的JSON字符串,所以当收到JSON格式的参数时,因无法解析,所以req.body就为空了
既然body-parser 只能解析序列化的表单数据格式 ,即“?username=username&password=passwrod”
我们只要将参数对象序列化成表单数据格式,再发送就好了。
这里要用到axios提供的 qs 库
qs是axios自带的一个库
里面的stringify方法可以将一个json对象 直接转为(以?和&符连接的形式) 。 在开发中,发送请求的入参大多是一个对象。在发送时,如果该请求为get请求,就需要对参数进行转化。使用该库,就可以自动转化,而不需要手动去拼接
所以我只要将我的参数对象 通过qs的stringfy方法转换为表单数据格式 ,再通过axios发送给服务器,body-parser就能解析成key,value的键值对形式,放入req.body中。

服务器控制台打印的req.body对象
