wx.request 的封裝
小程序提供了request的網(wǎng)絡(luò)接口,用于服務(wù)器交互距境。但是我們在開發(fā)的過程中發(fā)現(xiàn)了以下問題:
- 每個頁面中都要去寫一些重復(fù)的相關(guān)配置浊闪,比如header
- 沒有統(tǒng)一的loading提示管理
- 沒有統(tǒng)一的錯誤處理機(jī)制
- 頁面邏輯與請求服務(wù)器代碼混在一起,比較混亂本慕,不好調(diào)試
統(tǒng)一header問題
發(fā)起請求時峭跳,服務(wù)器有些接口需要驗證用戶身份膘婶,一般是會把用戶登錄之后的token設(shè)置在header中,回傳給服務(wù)器蛀醉,我們可以寫一個通用的方法:
/**
* 獲取header
*/
function getCommonHeader() {
let header = {
'Content-type': 'application/x-www-form-urlencoded'
};
// 如果token有值則帶上
let token = wx.getStorageSync("token");
if (token) {
header = Object.assign({}, header, {
'Authorization': 'Bearer ' + token
});
}
return header;
};
統(tǒng)一loading管理
為了防止用戶多次點擊以及更好的用戶體驗悬襟,一般發(fā)起請求時會加上loading動畫,服務(wù)器返回之后再去掉這個loading拯刁。但是產(chǎn)品設(shè)計時也有不加loading動畫和自定義loading文字的需求脊岳,所以我們可以添加一個控制開關(guān) showLoading
和 loadingTitle
,由外部調(diào)用時設(shè)置。
統(tǒng)一錯誤處理機(jī)制
這里需要和服務(wù)器約定統(tǒng)一返回結(jié)果格式割捅,比如:
{"code": 0, "data": "", "msg": "ok"}
解釋一下:
- code 表示本次請求的狀態(tài)碼
- data 是服務(wù)器返回的數(shù)據(jù)
- msg 業(yè)務(wù)錯誤提示
首先對此次請求的http狀態(tài)判斷奶躯,非 200 則表示此次請求失敗了,可能是 500 服務(wù)器報錯亿驾,也可能是 404 請求服務(wù)器url未找到等等嘹黔。
接著對業(yè)務(wù)狀態(tài)判斷,這個由服務(wù)器約定莫瞬,比如 0 表示成功儡蔓,非 0 則表示業(yè)務(wù)錯誤,一般直接 toast 提示服務(wù)器返回的 msg 就可以了疼邀,這樣就對服務(wù)器錯誤進(jìn)行了統(tǒng)一處理喂江。
但是和 loading 一樣,有些頁面需要有特殊的錯誤處理檩小,這時我們也添加一個控制開關(guān) showToast
开呐,由調(diào)用時控制是否顯示統(tǒng)一的錯誤信息。
接口promise化
為了調(diào)用時少些回調(diào)规求,我們把這個request接口包裝成一個promise,調(diào)用時直接使用 then
和 catch
來處理業(yè)務(wù)卵惦。最終的代碼如下:
/**
* 網(wǎng)絡(luò)請求
*/
function request(url, data = {}, header = {}, method = "POST", config = {}) {
// header 空值處理
let _header = {
"content-type": "application/x-www-form-urlencoded"
};
if (Object.keys(header).length > 0) {
_header = header;
}
let showToast = true,
showLoading = false,
loadingTitle = "加載中阻肿。。沮尿。";
// 默認(rèn)顯示toast
if (config['showToast'] != undefined && config['showToast'] == false) {
showToast = false;
}
// 默認(rèn)顯示loading
if (config['showLoading'] != undefined && config['showLoading'] == true) {
showLoading = true;
}
if (config['loadingTitle']) {
loadingTitle = config['loadingTitle'];
}
return new Promise((resolve, reject) => {
// 是否顯示loading
if (showLoading) {
wx.showLoading({ title: loadingTitle, icon: 'none', mask: true });
}
wx.request({
url: url,
data: data,
header: _header,
method: method,
success: (res => {
if (showLoading) {
wx.hideLoading();
}
// 服務(wù)器 非200 錯誤
if (res.statusCode && res.statusCode != 200) {
wx.showToast({ title: '服務(wù)器 ' + res.statusCode + ' 錯誤', icon: 'none' });
reject(res);
return;
}
if (res.data && res.data.code != 0) {
// 業(yè)務(wù)狀態(tài)非0 是否提示
if (showToast) {
wx.showToast({ title: res.data.msg, icon: 'none' });
}
reject(res);
return;
}
resolve(res.data);
}),
fail: (err => {
if (showLoading) {
wx.hideLoading();
}
if (err.errMsg.indexOf('url not in domain list') > -1) {
wx.showToast({ title: '請求url不在合法域名中丛塌,請打開調(diào)試模式', icon: 'none' });
}
reject(err);
})
});
});
};
對于 get 請求和 post 請求我們再包裝一下
/**
* get 網(wǎng)絡(luò)請求
*/
function getRequest(url, data = {}, header = {}, config = {}){
return request(url, data, "GET", header, config);
}
/**
* post 網(wǎng)絡(luò)請求
*/
function postRequest(url, data = {}, header = {}, config = {}){
return request(url, data, "POST", header, config);
}
我們看看調(diào)用的例子,將上面封裝好的request函數(shù)放到 utils.js里面畜疾,新建一個api.js文件:
const utils = require('../utils.js');
module.exports = {
getUserInfo: function(data, config = {}){
return utils.postRequest(
'http://api.xx.com/get_user_info',
data,
utils.getCommonHeaders(),
config
);
}
}
然后頁面調(diào)用:
const api = require('../api.js');
/**
* 生命周期函數(shù)--監(jiān)聽頁面加載
*/
onLoad: function (options) {
api.getUserInfo({
"user_id": "1"
}, {
"showLoading": "false",
"showToast": "false",
"loadingTitle": "登錄中"
})
.then(res => {
console.log(res);
});
}
一般情況下上面的 showLoading 參數(shù)等配置項可以不寫赴邻,用默認(rèn)就行,那頁面就更簡潔了
const api = require('../api.js');
api.getUserInfo({"user_id": "1"})
.then(res => {
console.log(res);
});