Vue中axios 表單POST提交
剛開始使用Vue,裡面的坑是一個接一個,今天就遇到一個axios POST傳參的問題。
因為後端要求是按表單提交的形式給他資料,
我需要在請求中傳遞引數,然後按官方文件的格式開始操作,程式碼如下:
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
注:此處是官方示例:點選開啟連結
開啟控制檯,報400,報錯資訊是:傳遞的引數不存在,但在請求中看的到引數,只是引數的格式是Request Payload,具體也沒看懂是什麼,總之知道就是引數格式不對,查閱資料找到兩種解決辦法,程式碼如下:
1.es6寫法
import qs from 'qs';
const data = { 'bar': 123 };
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
url,
};
axios(options);
2.
var params = new URLSearchParams(); params.append('param1', 'value1'); params.append('param2', 'value2'); axios.post('/foo', params);
參考:https://github.com/axios/axios#using-applicationx-www-form-urlencoded-format
經測試,這兩種辦法都可以
這個問題剛解決,後臺就拋給我一個問題,我的引數裡面要傳陣列呢,我以為直接按上面的做法就能一馬平川了,然而現實是殘酷的,崩盤!檢視官方文件發現,其實這個的解決也是非常的簡單,只需要在qs的方法中設定它的indices為false即可,如:
qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });
更多qs功能參考:https://www.npmjs.com/package/qs
vue框架推薦使用axios來發送ajax請求,之前我還寫過一篇部落格來講解如何在vue元件中使用axios。但之前做著玩用的都是get請求,現在我自己搭部落格時使用了post方法,結果發現後臺(node.js)完全拿不到前臺傳來的引數。後來進過一番探索,終於發現問題所在。
post提交資料的四種編碼方式
1.application/x-www-form-urlencoded
這應該是最常見的post編碼方式,一般的表單提交預設以此方式提交。大部分伺服器語言對這種方式都有很好的支援。在PHP中,可以用$_POST[“key”]的方式獲取到key的值,在node中我們可以使用querystring中介軟體對引數進行分離
app.post("/server",function(req,res){
req.on("data",function(data){
let key=querystring.parse(decodeURIComponent(data)).key;
console.log("querystring:"+key)
});
});
2.multipart/form-data
這也是一種比較常見的post資料格式,我們用表單上傳檔案時,必須使form表單的enctype屬性或者ajax的contentType引數等於multipart/form-data。使用這種編碼格式時傳送到後臺的資料長得像這樣子
不同欄位以--boundary開始,接著是內容描述資訊,最後是欄位具體內容。如果傳輸的是檔案,還要包含檔名和檔案型別資訊
3.application/json
axios預設提交就是使用這種格式。如果使用這種編碼方式,那麼傳遞到後臺的將是序列化後的json字串。我們可以將application/json與application/x-www-form-urlencoded傳送的資料進行比較
首先是application/json:
接著是application/x-www-form-urlencoded:
這裡可以明顯看出application/x-www-form-urlencoded上傳到後臺的資料是以key-value形式進行組織的,而application/json則直接是個json字串。如果在處理application/json時後臺還是採用對付application/x-www-form-urlencoded的方式將會產生問題。例如後臺node.js依然採用之前對付application/x-www-form-urlencoded的方法,那麼querystring.parse(decodeURIComponent(data))之後得到的資料是這樣子的
這個時候再querystring.parse(decodeURIComponent(data)).key只能獲取到undefined
4.text/xml
剩下的一種編碼格式是text/xml,這種格式我沒有怎麼使用過
解決方法
既然我們知道axios post方法預設使用application/json格式編碼資料,那麼解決方案就有兩種,一是後臺改變接收引數的方法,另一種則是將axios post方法的編碼格式修改為application/x-www-form-urlencoded,這樣就不需要後臺做什麼修改了。
先來看第一種解決方法
vue元件中,axios傳送post請求的程式碼如下
this.$axios({
method:"post",
url:"/api/haveUser",
data:{
name:this.name,
password:this.password
}
}).then((res)=>{
console.log(res.data);
})
此時控制檯Network Headers裡面的資訊是這樣子的
後臺接收資料需要依賴body-parser中介軟體,我們事先裝好,接著在後臺程式碼中引用body-parser
這張截圖中,發揮作用的程式碼僅僅是const bodyParser=require("body-parser");
接下來在路由中使用body-parser
app.post("/api/haveUser",bodyParser.json(),function(req,res){
console.log(req.body);
let haveUser=require("../api/server/user.js");
haveUser(req.body.name,req.body.password,res);
});
這時,當前臺傳送post請求之後,後臺控制檯中就會打印出req.body
這時,通過req.body.name或者req.body.password就能拿到對應的值。
這種方法比較簡單,也不需要前臺做過多修改,推薦使用這種方法。
第二種解決方法,具體操作如下
前端
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);
});
});
這種方法明顯就要比第一種麻煩一點,但不需要後臺做過多處理。所以具體操作還是得根據實際情況決定。