嘗試了一下Express中的post請求,原以為和get請求是一樣的段多。
axios的post請求的官方示例是這樣的:
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
但是結(jié)果發(fā)現(xiàn)首量,在后端無論如何都沒有返回我需要的數(shù)據(jù)。
原來衩匣,POST方法提交的數(shù)據(jù)有四種編碼方式蕾总。
1.application/x-www-form-urlencoded
這種方式是最常見的POST編碼方式粥航。瀏覽器的原生<form>
表單琅捏,如果不設(shè)置enctype
屬性,那么最終就會以 application/x-www-form-urlencoded
方式提交數(shù)據(jù)递雀。
很多時候柄延,我們用 Ajax 提交數(shù)據(jù)時,也是使用這種方式缀程。例如 JQuery 和 QWrap 的 Ajax搜吧,Content-Type 默認(rèn)值都是「application/x-www-form-urlencoded;charset=utf-8」。
- multipart/form-data
我們使用表單上傳文件時杨凑,必須讓 <form> 表單的 enctype 等于 multipart/form-data滤奈。
這種方式一般用來上傳文件,各大服務(wù)端語言對它也有著良好的支持撩满。
上面提到的這兩種 POST 數(shù)據(jù)的方式蜒程,都是瀏覽器原生支持的绅你,而且現(xiàn)階段標(biāo)準(zhǔn)中原生 <form> 表單也只支持這兩種方式(通過 <form> 元素的 enctype
屬性指定,默認(rèn)為 application/x-www-form-urlencoded
昭躺。其實(shí) enctype
還支持 text/plain
忌锯,不過用得非常少)。
隨著越來越多的 Web 站點(diǎn)领炫,尤其是 WebApp偶垮,全部使用 Ajax 進(jìn)行數(shù)據(jù)交互之后,我們完全可以定義新的數(shù)據(jù)提交方式帝洪,給開發(fā)帶來更多便利似舵。
3 .application/json
現(xiàn)在越來越多的人把它作為請求頭,用來告訴服務(wù)端消息主體是序列化后的 JSON 字符串葱峡。由于 JSON 規(guī)范的流行啄枕,除了低版本 IE 之外的各大瀏覽器都原生支持 JSON.stringify,服務(wù)端語言也都有處理 JSON 的函數(shù)族沃,使用 JSON 不會遇上什么麻煩频祝。
4.text/xml
它是一種使用 HTTP 作為傳輸協(xié)議,XML 作為編碼方式的遠(yuǎn)程調(diào)用規(guī)范脆淹。XML-RPC 協(xié)議簡單常空、功能夠用,各種語言的實(shí)現(xiàn)都有盖溺。它的使用也很廣泛漓糙,如 WordPress 的 XML-RPC Api,搜索引擎的 ping 服務(wù)等等烘嘱。JavaScript 中昆禽,也有現(xiàn)成的庫支持以這種方式進(jìn)行數(shù)據(jù)交互,能很好的支持已有的 XML-RPC 服務(wù)。
相比之下砰逻,get方式的數(shù)據(jù)提交方式(編碼方式)只有一種堕花,就是application/x-www-form-urlencoding
我們的axios用的就是第三種編碼方式,也就是application/json
盗棵,但是Express的post默認(rèn)是第一種方式,所以我們就找不到我們要的數(shù)據(jù)了北发。
問題找到了纹因,就要想辦法解決問題。既然是前后端的數(shù)據(jù)編碼方式不一樣琳拨,那么只要想辦法讓他們一樣就行了瞭恰。
首先,把后端的接收格式改成application/json
狱庇。在Express中惊畏,我們需要用到一個叫做bodyParser的中間件是牢。
引入body-parser:
$ npm install body-parser --save
基本使用:
var express = require('express')
//獲取模塊
var bodyParser = require('body-parser')
var app = express()
// 創(chuàng)建 application/json 解析
var jsonParser = bodyParser.json()
// 創(chuàng)建 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數(shù)據(jù)
2. bodyParser.raw(options): 解析二進(jìn)制格式(Buffer流數(shù)據(jù))
3. bodyParser.text(options): 解析文本數(shù)據(jù)
4. bodyParser.urlencoded(options): 解析UTF-8的編碼的數(shù)據(jù)。
最后陕截,bodyParser變量是對中間件的引用驳棱。請求體解析后,解析值都會被放到req.body
屬性农曲,所以直接拿出來就行了社搅。
有的時候后端已經(jīng)固定了,沒有辦法只能改前端乳规。
前端:
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);
})
其中發(fā)揮關(guān)鍵作用的是headers與transformRequest形葬。其中 headers 是設(shè)置即將被發(fā)送的自定義請求頭。 transformRequest 允許在向服務(wù)器發(fā)送前暮的,修改請求數(shù)據(jù)笙以。這樣操作之后,后臺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);
});
});
參考文獻(xiàn):
瀏覽器行為:Form表單提交
post提交數(shù)據(jù)的四種編碼方式
Express 中間件----body-parser(五)