Express無法通過req.body獲取請求傳遞的數(shù)據(jù)解決方法
前言
最近嘗試重新封裝XMLHttpRequest
,在發(fā)post
請求的時候,發(fā)現(xiàn)express
通過req.body
獲取不到數(shù)據(jù),req.body
打印出來是一個空對象。
網(wǎng)上也試了網(wǎng)上各種辦法,還是不成功,最后發(fā)現(xiàn)需要在XMLHttpRequest
請求時設(shè)置一個請求頭,來標(biāo)識發(fā)送過去數(shù)據(jù)的類型。
1、問題描述
服務(wù)端代碼如下:創(chuàng)建了一個/login
請求,在控制臺輸出請求數(shù)據(jù)。
// 創(chuàng)建應(yīng)用對象 const express = require('express'); const bodyParser = require('body-parser'); // 創(chuàng)建應(yīng)用對象 const app = express(); app.use((req,res,next)=>{ //針對跨域進(jìn)行配置,允許任何源訪問 res.header('Access-Control-Allow-Origin', "*") next() }) // 創(chuàng)建路由規(guī)則 app.post("/login", (req,res) =>{ // 輸出req.body console.log("req.body:", req.body); res.send("login success") }) // 監(jiān)聽端口啟動服務(wù) app.listen(8002,() => { console.log("服務(wù)已啟動,8002端口監(jiān)聽中..."); })
前端代碼如下:
<!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>
明明已經(jīng)通過xml.send(JSON.stringify(data))
已經(jīng)將數(shù)據(jù)轉(zhuǎn)換成json
格式傳到后端,我們可以打開network
查看。
但是express
中就是獲取不到{"username":"test","password":"123"}
,控制臺輸出了一個空對象。
2、 解決辦法
2.1 解決JSON內(nèi)容格式
查了網(wǎng)上的教程,可以通過引入中間件'body-parser'
:它是一個HTTP
請求體解析中間件,它用于解析客戶端請求的body
中的內(nèi)容,如application/x-www-form-urlencoded
、application/json
這兩種常用的內(nèi)容格式。
配置后代碼如下:
// 創(chuàng)建應(yīng)用對象 const express = require('express'); // 執(zhí)行npm install body-parser之后再引入 const bodyParser = require('body-parser'); // 創(chuàng)建應(yīng)用對象 const app = express(); // 處理application/json內(nèi)容格式的請求體 app.use(bodyParser.json()); app.use((req,res,next)=>{ //實(shí)驗(yàn)驗(yàn)證,只需要設(shè)置這一個就可以進(jìn)行g(shù)et請求 res.header('Access-Control-Allow-Origin', "*")//配置8080端口跨域 next() }) // 創(chuàng)建路由規(guī)則 app.post("/login", (req,res) =>{ // console.log(req); console.log("req.body:", req.body); res.send("login success") }) // 監(jiān)聽端口啟動服務(wù) app.listen(8002,() => { console.log("服務(wù)已啟動,8002端口監(jiān)聽中..."); })
但是依舊獲取不到?。?!
原因:在請求中,沒有設(shè)置請求頭,也就是沒有指明你傳遞的是什么格式的數(shù)據(jù),需要通過xml.setRequestHeader("Content-Type","application/json")
或者通過xml.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
設(shè)置請求頭中Content-Type
值。
前端請求中補(bǔ)充xml.setRequestHeader("Content-Type","application/json")
xml.open("post", url , true) // 添加Content-Type這個請求頭 xml.setRequestHeader("Content-Type","application/json"); xml.send(JSON.stringify(data))
同時在服務(wù)端配置跨域請求允許的訪問頭,如果不配置res.header('Access-Control-Allow-Headers', 'Content-Type')
,則會出現(xiàn)以下提示content-type is not allowed
。
跨域配置,配置請求中可攜帶請求頭Content-Type
app.use((req,res,next)=>{ //針對跨域進(jìn)行配置,允許任何源訪問 res.header('Access-Control-Allow-Origin', "*") // 允許前端請求中包含Content-Type這個請求頭 res.header('Access-Control-Allow-Headers', 'Content-Type') next() })
經(jīng)過這樣配置,即可在服務(wù)端成功獲取前端傳遞來的數(shù)據(jù):
2.2、解決x-www-form-urlencoded內(nèi)容格式
首先,我們再配置一個獲取application/x-www-form-urlencoded
內(nèi)容格式的路由。之后通過配置app.use(bodyParser.urlencoded({extended: false}));
即可
服務(wù)端代碼如下:
// 創(chuàng)建應(yīng)用對象 const express = require('express'); // 執(zhí)行npm install body-parser之后再引入 const bodyParser = require('body-parser'); // 創(chuàng)建應(yīng)用對象 const app = express(); // 處理application/json內(nèi)容格式的請求體 app.use(bodyParser.json()); // 處理application/x-www-form-urlencoded內(nèi)容格式的請求體 app.use(bodyParser.urlencoded({extended: false})); app.use((req,res,next)=>{ //針對跨域進(jìn)行配置,允許任何源訪問 res.header('Access-Control-Allow-Origin', "*") // 允許前端請求中包含Content-Type這個請求頭 res.header('Access-Control-Allow-Headers', 'Content-Type') next() }) // 創(chuàng)建路由規(guī)則 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") }) // 監(jiān)聽端口啟動服務(wù) app.listen(8002,() => { console.log("服務(wù)已啟動,8002端口監(jiān)聽中..."); })
前端代碼如下:添加了一個登錄2
按鈕,同時綁定了它的請求方法。注意x-www-form-urlencoded
這種請求的數(shù)據(jù)格式為: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(){ // 創(chuàng)建XMLHttpRequest實(shí)例 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(){ // 創(chuàng)建XMLHttpRequest實(shí)例 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>
如下圖所示:可見數(shù)據(jù)已經(jīng)發(fā)送到后端。
同時,后端可以通過req.body
成功獲取到數(shù)據(jù)。
但是數(shù)據(jù)前面有一個Object: null prototype
,這個是不影響取值的,按照上面這個例子,我們依舊可以通過req.body.username
與req.body.password
獲取到對應(yīng)的數(shù)據(jù)。
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") })
當(dāng)然,我們也可以通過先對對象進(jìn)行JSON
字符串轉(zhuǎn)化JSON.stringify()
,然后再轉(zhuǎn)化成對象JSON.parse()
,這樣就可以將其去除了。
app.post("/login2", (req,res) =>{ console.log(JSON.parse(JSON.stringify(req.body))); res.send("login2 success") })
3、附
3.1、獲取get請求參數(shù)
通過req.query
來獲取get請求參數(shù)
服務(wù)端代如下:我們再配置一個/data
的路由。
// 創(chuàng)建路由規(guī)則 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">獲取數(shù)據(jù)</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請求中參數(shù)是放在url中 url3 = "http://localhost:8002/data?id=3" dom.addEventListener("click",function(){ // 創(chuàng)建XMLHttpRequest實(shí)例 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(){ // 創(chuàng)建XMLHttpRequest實(shí)例 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(){ // 創(chuàng)建XMLHttpRequest實(shí)例 let xml = new XMLHttpRequest() xml.onreadystatechange = function(){ if(xml.readyState == 4){ console.log(xml.responseText); } } xml.open("get", url3 , true) // get請求參數(shù)是放在url中,而不是通過xml.send()發(fā)送過去,不可以使用以下寫法:xml.send("id=3") xml.send() }) // console.log(a); // let a = 1 </script> </body> </html>
成功通過req.query
獲取到get
的請求參數(shù)
3.2、封裝XMLHttpRequest
上面的請求代碼太冗余,寫了好多let xml = new XMLHttpRequest()、xml.open()、xml.send()
等。我的本意是想著封裝一下XMLHttpRequest
,碰巧遇到了這個post
參數(shù)取不到的問題?,F(xiàn)在回到最開始,對XMLHttpRequest做一個簡單的封裝吧。
ajax.js代碼如下:
(function () { const AJAX = function (options) { try { // 1、解析參數(shù) var method = options.method var url = options.url var data = options.data var contentType = options.contentType || "json" var headers = options.headers var async = options.async || false var successCallback = options.successCallback || function () { } var errorCallback = options.errorCallback || function (err) { console.log(err); } } catch (err) { console.log("Parsing parameter error") } try { // 2、創(chuàng)建XMLHttpRequest或ActiveXObject對象 var xhr = null if (window.XMLHttpRequest) { xhr = new XMLHttpRequest() } else { // 兼容IE6, IE5 xhr = new ActiveXObject("Microsoft.XMLHTTP"); } // 3、設(shè)置get請求參數(shù) if (method == "get") { var params = "" if (data) { for (v in data) { params += v + "=" + data[v] + "&" } params = params.replace(/&$/, ""); xhr.open(method, url + "?" + params, async) xhr.send() } else { xhr.open(method, url, async) xhr.send() } } else if (method == "post") { // 設(shè)置post請求參數(shù) xhr.open(method, url, async) if (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)) } // 設(shè)置請求頭 if (headers) { for (h in headers) { if (h == "Content-Type") { continue } xhr.setRequestHeader(h, headers.h) } } xhr.onreadystatechange = function () { // 成功回調(diào) if (xhr.readyState == 4 && xhr.status == 200) { successCallback() } } xhr.onerror = function (err) { // 失敗回調(diào) errorCallback(err); } return xhr.response } catch (err) { console.log("Request Error"); } } // 將AJAX對象暴露到window對象上 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">獲取數(shù)據(jù)</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、總結(jié)
首先分析了req.body
獲取不到數(shù)據(jù)的原因,之后給出了解決辦法,通過設(shè)置響應(yīng)頭、使用中間件、配置跨域請求這三種方式來解決獲取不到數(shù)據(jù)的問題。最后簡單的封裝了XMLHttpRequest
。
以上就是Express無法通過req.body獲取請求傳遞的數(shù)據(jù)解決方法的詳細(xì)內(nèi)容,更多關(guān)于Express req.body請求傳遞的資料請關(guān)注腳本之家其它相關(guān)文章!
- node.js使用express-jwt報(bào)錯:expressJWT?is?not?a?function解決
- 解決React報(bào)錯Expected an assignment or function call and instead saw an expression
- React報(bào)錯信息之Expected?an?assignment?or?function?call?and?instead?saw?an?expression
- MySQL運(yùn)行報(bào)錯:“Expression?#1?of?SELECT?list?is?not?in?GROUP?BY?clause?and?contains?nonaggre”解決方法
- 解決三元運(yùn)算符 報(bào)錯“SyntaxError: can''''t assign to conditional expression”
- 解決大于5.7版本mysql的分組報(bào)錯Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated
- express框架,報(bào)錯:“Cannot set headers after they are sent to the client”,解決方法總結(jié)
相關(guān)文章
JavaScript indexOf的第二個參數(shù)用法
indexOf 是我們非常熟悉的一個方法,它可以用來獲取某一個元素在一個數(shù)組里的位置,我們一般就會使用 array.indexOf(element) 的方法來進(jìn)行使用,但是,大家有沒有使用過 indexOf 的第二個參數(shù)呢?本文將給大家介紹一下indexOf的第二個參數(shù)用法,需要的朋友可以參考下2024-02-02js將多維數(shù)組轉(zhuǎn)為一維數(shù)組后去重排序
本文主要介紹了js將多維數(shù)組轉(zhuǎn)為一維數(shù)組后去重排序,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-06-06js獲取url中的參數(shù)且參數(shù)為中文時通過js解碼
這篇文章主要介紹了url中傳遞中文參數(shù)的時候通過js解碼,需要的朋友可以參考下2014-03-03JavaScript實(shí)現(xiàn)選中文字提示新浪微博分享效果
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)選中文字提示新浪微博分享效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06JavaScript 就地編輯HTML節(jié)點(diǎn)實(shí)現(xiàn)代碼
JavaScript 就地編輯HTML節(jié)點(diǎn)實(shí)現(xiàn)代碼2009-07-07js實(shí)現(xiàn)固定顯示區(qū)域內(nèi)自動縮放圖片的方法
這篇文章主要介紹了js實(shí)現(xiàn)固定顯示區(qū)域內(nèi)自動縮放圖片的方法,實(shí)例分析了javascript操作頁面元素及屬性的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-07-07使用contextMenu插件實(shí)現(xiàn)Bootstrap table彈出右鍵菜單
如今Bootstrap這個前端框架已被許多人接受并應(yīng)用在不同的項(xiàng)目中,其中“開發(fā)高效,設(shè)備兼容”的特點(diǎn)表現(xiàn)得非常明顯。這篇文章主要介紹了使用contextMenu插件實(shí)現(xiàn)Bootstrap table彈出右鍵菜單,需要的朋友可以參考下2017-02-02