前言
最近尝试重新封装XMLHttpRequest,在发post请求的时候,发现express通过req.body获取不到数据,req.body打印出来是一个空对象。网上也试了网上各种办法,还是不成功,最后发现需要在XMLHttpRequest请求时设置一个请求头,来标识发送过去数据的类型。
1、问题描述
服务端代码如下:创建了一个
/login请求,在控制台输出请求数据。
// 创建应用对象
const express = require('express');
const bodyParser = require('body-parser');
// 创建应用对象
const app = express();
app.use((req,res,next)=>{//针对跨域进行配置,允许任何源访问res.header('Access-Control-Allow-Origin', "*")next()
})// 创建路由规则
app.post("/login", (req,res) =>{// 输出req.bodyconsole.log("req.body:", req.body);res.send("login success")
})
// 监听端口启动服务
app.listen(8002,() => {console.log("服务已启动,8002端口监听中...");
})
前端代码如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><button id="login">登录</button><script> let dom = document.getElementById("login")url = "http://localhost:8002/login"
dom.addEventListener("click",function(){let xml = new XMLHttpRequest()let data = {"username":"test","password":"123"}xml.onreadystatechange = function(){if(xml.readyState == 4){console.log(xml.responseText);}}xml.open("post", url , true)xml.send(JSON.stringify(data))}) </script>
</body>
</html>
明明已经通过xml.send(JSON.stringify(data))已经将数据转换成json格式传到后端,我们可以打开network查看。
但是express中就是获取不到{"username":"test","password":"123"},控制台输出了一个空对象。
2、 解决办法
2.1 解决JSON内容格式
查了网上的教程,可以通过引入中间件
'body-parser':它是一个HTTP请求体解析中间件,它用于解析客户端请求的body中的内容,如application/x-www-form-urlencoded、application/json这两种常用的内容格式。
配置后代码如下:
// 创建应用对象
const express = require('express');
// 执行npm install body-parser之后再引入
const bodyParser = require('body-parser');
// 创建应用对象
const app = express();
// 处理application/json内容格式的请求体
app.use(bodyParser.json());
app.use((req,res,next)=>{//实验验证,只需要设置这一个就可以进行get请求res.header('Access-Control-Allow-Origin', "*")//配置8080端口跨域next()
})
// 创建路由规则
app.post("/login", (req,res) =>{// console.log(req);console.log("req.body:", req.body);res.send("login success")
})
// 监听端口启动服务
app.listen(8002,() => {console.log("服务已启动,8002端口监听中...");
})
但是依旧获取不到!!!
原因:在请求中,没有设置请求头,也就是没有指明你传递的是什么格式的数据,需要通过xml.setRequestHeader("Content-Type","application/json")或者通过xml.setRequestHeader("Content-Type","application/x-www-form-urlencoded");设置请求头中Content-Type值。
前端请求中补充
xml.setRequestHeader("Content-Type","application/json")
xml.open("post", url , true)
// 添加Content-Type这个请求头
xml.setRequestHeader("Content-Type","application/json");
xml.send(JSON.stringify(data))
同时在服务端配置跨域请求允许的访问头,如果不配置res.header('Access-Control-Allow-Headers', 'Content-Type'),则会出现以下提示content-type is not allowed。
跨域配置,配置请求中可携带请求头Content-Type
app.use((req,res,next)=>{//针对跨域进行配置,允许任何源访问res.header('Access-Control-Allow-Origin', "*")// 允许前端请求中包含Content-Type这个请求头res.header('Access-Control-Allow-Headers', 'Content-Type')next()
})
经过这样配置,即可在服务端成功获取前端传递来的数据:
2.2、解决x-www-form-urlencoded内容格式
首先,我们再配置一个获取application/x-www-form-urlencoded内容格式的路由。之后通过配置app.use(bodyParser.urlencoded({extended: false}));即可
服务端代码如下:
// 创建应用对象
const express = require('express');
// 执行npm install body-parser之后再引入
const bodyParser = require('body-parser');
// 创建应用对象
const app = express();
// 处理application/json内容格式的请求体
app.use(bodyParser.json());
// 处理application/x-www-form-urlencoded内容格式的请求体
app.use(bodyParser.urlencoded({extended: false}));
app.use((req,res,next)=>{//针对跨域进行配置,允许任何源访问res.header('Access-Control-Allow-Origin', "*")// 允许前端请求中包含Content-Type这个请求头res.header('Access-Control-Allow-Headers', 'Content-Type')next()
})// 创建路由规则
app.post("/login", (req,res) =>{// console.log(req);console.log("req.body:", req.body);res.send("login success")
})
app.post("/login2", (req,res) =>{// console.log(req);console.log(req.body);res.send("login2 success")
})
// 监听端口启动服务
app.listen(8002,() => {console.log("服务已启动,8002端口监听中...");
})
前端代码如下:添加了一个
登录2按钮,同时绑定了它的请求方法。注意x-www-form-urlencoded这种请求的数据格式为:key=value&key=value
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><button id="login">登录</button><button id="login2">登录2</button><script> let dom = document.getElementById("login")let dom2 = document.getElementById("login2")url = "http://localhost:8002/login"url2 = "http://localhost:8002/login2"
dom.addEventListener("click",function(){// 创建XMLHttpRequest实例let xml = new XMLHttpRequest()// 请求体let data = {"username":"test","password":"123"}xml.onreadystatechange = function(){if(xml.readyState == 4){console.log(xml.responseText);}}xml.open("post", url , true)xml.setRequestHeader("Content-Type","application/json");xml.send(JSON.stringify(data))}) dom2.addEventListener("click",function(){// 创建XMLHttpRequest实例let xml = new XMLHttpRequest()xml.onreadystatechange = function(){if(xml.readyState == 4){console.log(xml.responseText);}}xml.open("post", url2 , true)xml.setRequestHeader("Content-Type","application/x-www-form-urlencoded");xml.send('username=test&password=123')}) </script>
</body>
</html>
如下图所示:可见数据已经发送到后端。
同时,后端可以通过req.body成功获取到数据。
但是数据前面有一个Object: null prototype,这个是不影响取值的,按照上面这个例子,我们依旧可以通过req.body.username与req.body.password获取到对应的数据。
app.post("/login2", (req,res) =>{// console.log(req);console.log(req.body);console.log(req.body.username);console.log(req.body.password);res.send("login2 success")
})
当然,我们也可以通过先对对象进行JSON字符串转化JSON.stringify(),然后再转化成对象JSON.parse(),这样就可以将其去除了。
app.post("/login2", (req,res) =>{console.log(JSON.parse(JSON.stringify(req.body)));res.send("login2 success")
})
3、附
3.1、获取get请求参数
通过req.query来获取get请求参数
服务端代如下:我们再配置一个
/data的路由。
// 创建路由规则
app.get('/data',(req,response) => {let obj = {name:'test',age:18}console.log(req.query);response.send(obj)
});
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><button id="login">登录</button><button id="login2">登录2</button><button id="getinfo">获取数据</button><script> let dom = document.getElementById("login")let dom2 = document.getElementById("login2")let dom3 = document.getElementById("getinfo")url = "http://localhost:8002/login"url2 = "http://localhost:8002/login2"// get请求中参数是放在url中url3 = "http://localhost:8002/data?id=3"
dom.addEventListener("click",function(){// 创建XMLHttpRequest实例let xml = new XMLHttpRequest()// 请求体let data = {"username":"test","password":"123"}xml.onreadystatechange = function(){if(xml.readyState == 4){console.log(xml.responseText);}}xml.open("post", url , true)xml.setRequestHeader("Content-Type","application/json");xml.send(JSON.stringify(data))}) dom2.addEventListener("click",function(){// 创建XMLHttpRequest实例let xml = new XMLHttpRequest()xml.onreadystatechange = function(){if(xml.readyState == 4){console.log(xml.responseText);}}xml.open("post", url2 , true)xml.setRequestHeader("Content-Type","application/x-www-form-urlencoded");xml.send('username=test&password=123')}) dom3.addEventListener("click",function(){// 创建XMLHttpRequest实例let xml = new XMLHttpRequest()xml.onreadystatechange = function(){if(xml.readyState == 4){console.log(xml.responseText);}}xml.open("get", url3 , true)// get请求参数是放在url中,而不是通过xml.send()发送过去,不可以使用以下写法:xml.send("id=3")xml.send()}) // console.log(a);// let a = 1 </script>
</body>
</html>
成功通过req.query获取到get的请求参数
3.2、封装XMLHttpRequest
上面的请求代码太冗余,写了好多let xml = new XMLHttpRequest()、xml.open()、xml.send()等。我的本意是想着封装一下XMLHttpRequest,碰巧遇到了这个post参数取不到的问题。现在回到最开始,对XMLHttpRequest做一个简单的封装吧。
ajax.js代码如下:
(function () {const AJAX = function (options) {try {// 1、解析参数var method = options.methodvar url = options.urlvar data = options.datavar contentType = options.contentType || "json"var headers = options.headersvar withCredentials = options.withCredentials || falsevar async = options.async || falsevar successCallback = options.successCallback || function () { }var errorCallback = options.errorCallback || function (err) { console.log(err); }} catch (err) {console.log("Parsing parameter error")}// try {// 2、创建XMLHttpRequest或ActiveXObject对象var xhr = nullif (window.XMLHttpRequest) {xhr = new XMLHttpRequest()} else {// 兼容IE6, IE5 xhr = new ActiveXObject("Microsoft.XMLHTTP");}// 3、设置get请求参数if (method == "get") {var params = ""if (data) {for (v in data) {params += v + "=" + data[v] + "&"}params = params.replace(/&$/, "");xhr.open(method, url + "?" + params, async)} else {xhr.open(method, url, async)}// 设置请求头if (headers) {for (h in headers) {if (h == "Content-Type") {continue}xhr.setRequestHeader(h, headers[h])}}// 设置请求携带cookiexhr.withCredentials = withCredentialsxhr.send()} else if (method == "post") {// 设置post请求参数xhr.open(method, url, async)// 设置请求头if (headers) {for (h in headers) {if (h == "Content-Type") {continue}xhr.setRequestHeader(h, headers[h])}}xhr.withCredentials = withCredentialsif (contentType == "application/x-www-form-urlencoded; charset=UTF-8") {xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");} else if (contentType == "application/json") {xhr.setRequestHeader("Content-Type", "application/json");}xhr.send(JSON.stringify(data))}xhr.onreadystatechange = function () {// 成功回调if (xhr.readyState == 4 && xhr.status == 200) {successCallback()}}xhr.onerror = function (err) {// 失败回调errorCallback(err);}return xhr.response// } catch (err) {// console.log("Request Error");// }}window.AJAX = AJAX
})(window)
html代码:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="../ajax.js"></script>
</head>
<body><button id="login">登录</button><button id="login2">登录2</button><button id="getinfo">获取数据</button><script> let dom = document.getElementById("login")let dom2 = document.getElementById("login2")let dom3 = document.getElementById("getinfo")url = "http://localhost:8002/login"url2 = "http://localhost:8002/login2"url3 = "http://localhost:8002/data?id=3"
dom.addEventListener("click",function(){let options = {method:"post",url:"http://localhost:8002/login",data:{"username":"test","password":"123"},contentType:"application/json"}let res = AJAX(options)console.log("res", res);}) dom2.addEventListener("click",function(){let options = {method:"post",url:"http://localhost:8002/login2",data:{"username":"test","password":"123"},contentType:"application/x-www-form-urlencoded; charset=UTF-8"}let res = AJAX(options)console.log("res", res);}) dom3.addEventListener("click",function(){let options = {method:"get",url:"http://localhost:8002/data",data:{"id": 1}}let res = AJAX(options)console.log("res", res);}) </script>
</body>
</html>
4、总结
首先分析了req.body获取不到数据的原因,之后给出了解决办法,通过设置响应头、使用中间件、配置跨域请求这三种方式来解决获取不到数据的问题。最后简单的封装了XMLHttpRequest。
最后
整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享
部分文档展示:




文章篇幅有限,后面的内容就不一一展示了
有需要的小伙伴,可以点下方卡片免费领取
当在Express中尝试通过req.body获取POST请求数据失败时,问题可能出在请求头未正确设置。解决方法包括:1) 使用body-parser中间件解析JSON或x-www-form-urlencoded内容;2) 设置请求头,指定数据格式;3) 配置跨域请求允许的头信息。通过这些步骤,可以在服务端成功接收前端传递的数据。
8896

被折叠的 条评论
为什么被折叠?



