vue中axios請求payload的暴力解決方案
去年公司做了一個小程式商城專案,運營了一段時間決定再次開發一個H5商城,用於微信好友之間的分享以及app內的巢狀,於是便開了一個vue專案,介面大多都是複用小程式的。
在做專案的過程中本人遇到一個由axios導致的問題——後臺介面拿不到請求的引數。因為介面都是之前寫好的,並且小程式執行正常,便沒有去讓後臺檢視,決定自己找出解決方案。開啟瀏覽器檢視引數發現axios的引數是這樣子的。
首先我解釋下我們這個奇葩的引數。(其實網上有兩種解決方案,但是由於這個引數,那兩種方案都不能使用,我才不得不使用第三種暴力解決方案,下面會講到。)我們的這個介面的引數goodsId的值是一個json字串,該
那麼想找出問題,我就要知道這個請求與小程式請求有什麼不同,於是開啟小程式,可以看到如下圖。
在這兩次請求中,可以看出引數有明顯的不同,axios的引數是由resquest payload傳遞的在引數之上還有一層大括號。而小程式的則是由form data傳遞的。
在請求中,決定引數形式的是標頭檔案中的content-type。再觀察我們可以看到兩者的content-type是不同的,前者是application/json,以json的方式請求,由於
知道了原因,就可以解決問題了。其實最方便的解決方式是與後臺溝通,讓他們相容一下。但是當時我們後臺忙於其他問題,這種可以前端解決的問題,就沒有去麻煩他們。那麼這種問題該如何解決呢。
一,更改params
這種方式我們不更改content-type,直接對引數進行改變,將引數改成?id=id&name=name的形式放在url上。
但是這種形式並不適合我們這種帶特殊符號的引數,在轉換過程中會出現轉義字元,並不能請求成功,因此我又去尋找第二種方式。function objToUrl(obj) { let str = '?' if(Object.prototype.toString.call(obj) === '[object Object]') { for (let key in obj) { if (key && obj.hasOwnProperty(key)) { str+=`${key}=${obj[key]}&` objToUrl(obj[key]) } } } return str } export function fetchPost (url, params){ let str = objToUrl(params) // let str = qs.stringify(params) return new Promise((resolve, reject) => { axios.post(url+str) .then(response => { resolve(response.data) }) .catch(error => { reject(error) }) })
二 更改content-type
這種方式是由開發者對axios進行封裝,首先更改axios的content-type,改為我們熟悉的。
'Content-Type': 'application/x-www-form-urlencoded'
程式碼:axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'
假設你的引數為{‘bar’:’aaa’},那麼需要對引數進行一下處理:qs.stringify({‘bar’:’aaa’})
程式碼為:
export function fetchPost (url, params){
params = qs.stringify(params)
return new Promise((resolve, reject) => {
axios.post(url,params,{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(response => {
resolve(response.data)
})
.catch(error => {
reject(error)
})
})
}
第二種方式滿足了我的需求,但是前幾天我再次踩到了axios的坑,因此一氣之下開始了第三種方案,暴力解決!三 暴力解決方案
在後面的介面中,我們用到了一個比較複雜的json,其中包含了一個數組,這時使用第二種方案就出現了一種問題。
如圖所示,qs在處理我的引數時,把陣列處理成了cartIds[index]: value的格式,這顯然不能讓後端成功接收。於是我便著手研究第三種方案。
其實無論是axios還是之前的vue-resource,本質上都是ajax請求,而最最原始暴力的方式,便是用原生封裝一個ajax,無論外掛裡出了什麼么蛾子,都能平靜對待。於是便有了如下程式碼:
// 暴力解決方案
export function fetchPost2 (url, params){
return new Promise((resolve, reject) => {
let xhr = new window.XMLHttpRequest()
xhr.open('POST', url, true)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
if(window.sessionStorage.getItem('setUserInfo')){
let userInfo = JSON.parse(window.sessionStorage.getItem('setUserInfo'))
xhr.setRequestHeader('Authentication', '')
xhr.setRequestHeader('X-User', userInfo.id)
}
xhr.setRequestHeader('X-Channel', '')
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && (xhr.status === 200 || xhr.status === 304)) {
resolve(JSON.parse(xhr.responseText))
}else{
// reject(error)
}
}
xhr.send(params)
})
}
是這裡的params也需要進行處理,處理成‘key=value&key=value’的形式,暫時解決了問題。(標頭檔案的設定是因為我們介面需要簽名)
事實證明原生可以解決一切問題~
(經過查閱發現,可以在qs中新增引數解決這個問題,如:params = qs.stringify(params,{ indices: false })。不過既然都用原生封裝了,就暫時這麼用了~當複習js基礎了)
四 後臺解決問題
這種問題好像只出現在java後臺。因為我在做這個專案的時候,後臺已經寫好介面並忙於其他專案,就沒有去麻煩人家,但是從網上的一些文章看來,後臺處理也可以完美解決這個問題。
如果出現這種狀況,說明後臺取引數是用@RequsetParam取引數的,讓後臺人員加上@RequestBody 註解就行了。
由於本人對後臺不是很瞭解,在此不加拓展,如果你是在開發中遇到了這個問題,可以和java後臺商量解決,當然如果你遇到了我這樣的情況,也可以暴力解決。
(但axios封裝自有他的好處,優化的話是否是直接修改axios的原生程式碼更好呢?希望有大神告知更好的解決辦法。)