这次花了很大精力,完整的写了一套通用的请求库,带拦截器功能
Why do this ?
简单点,用Promise把请求成功后的data给resolve了,失败后的error给reject了就行了。
但因为这次需要loading,判断token,而且所有接口都需要在header中添加token请求,简单的包一层Promise未免有些力不从心了。
这次封装的是微信小程序自带的请求方法,其实可以推广到所有异步请求的类库。
intercor achieve
具体讲讲interceptor的实现
initialization
类中存一个interceptor对象,这个对象自带两个Queue,请求前执行的函数和请求结束执行的函数。
因为请求之后会有成功和失败,所以这个Queue有successFunc、failFunc
对外开放添加拦截器的方法
process
在请求开始之前,调用request时传来的config不会立即带入,先扔进请求拦截器,对config做一些处理之后,再将config落实到请求方法上。
在请求结束后,将返回的数据不会立即返回,而是先扔进响应拦截器,正常执行的话,走successFunc,另一种情况请求失败reject时被catch住,在catch里执行failFunc。
在请求结束后的两种分支下返回本次请求的结果
下面给出具体代码
// 存放BaseURL的配置文件
const devConfig = require("./config");
// 网络请求文件request.js
class Axios {
constructor(config) {
this.config = Object.assign(
{
timeout: 3_000,
dataType: "json",
},
config
);
//拦截器对象
this.interceptor = {
reqQueue: [],
resQueue: [],
request(configFunc) {
this.reqQueue.push(configFunc);
},
response(successFunc, failFunc) {
this.resQueue.push({
successFunc,
failFunc,
});
},
};
//添加GET,POST.PUT.DELETE四种方法
["post", "get", "put", "delete"].reduce((pre, method) => {
pre[method] = function (url, data, shouldLoding) {
return this.request.call(
this,
Object.assign(this.config || {}, {
url,
method,
data: data || {},
shouldLoding: shouldLoding === undefined ? true : false,
})
);
};
return pre;
}, this);
}
async request(conf) {
//执行request拦截器
const config = this.interceptor.reqQueue.reduce(
(prev, cur) => cur.call(this, prev),
conf
);
try {
let res = await new Promise((resolve, reject) => {
wx.request({
method: config.method,
url: devConfig.host + config.url,
data: config.data || {},
header: config.header || {
"content-type": "application/json",
},
success(res) {
resolve(res);
},
fail(err) {
reject(err);
},
});
});
//成功响应拦截器
try {
for (const interceptor of this.interceptor.resQueue) {
res = await interceptor.successFunc.call(this, res);
}
return res;
} catch (InterceptorError) {
return Promise.reject(InterceptorError);
} //ok response
} catch (HTTPError) {
// 失败响应拦截器
try {
let error = HTTPError;
for (const interceptor of this.interceptor.resQueue) {
error = await interceptor.failFunc.call(this, error);
}
return error;
} catch (InterceptorError) {
return Promise.reject(InterceptorError);
} // fail response
}
}
}
module.exports = axios;
在文件中添加几个拦截器测试
let axios = new Axios();
//请求拦截器
axios.interceptor.request((config) => {
// 请求前loding
if (config.shouldLoding) {
wx.showLoading({
title: "正在加载中...",
icon: "loading",
});
}
// 判断本地是否存在token
let token = wx.getStorageSync("token");
if (!token) {
wx.showToast({
title: "未登录,请先登录!",
icon: "loading",
});
setTimeout(() => {
wx.switchTab({
url: "/pages/user/index",
});
}, 2_000);
}
config["header"] = {
Authorization: token,
"Content-Type": "application/x-www-form-urlencoded",
};
return config || {};
});
//响应拦截器
const UNLOGIN = 401;
axios.interceptor.response(
(res) => {
// 结束loding
wx.hideLoading();
// 未登录, reject结束业务流程
if (res.statusCode === UNLOGIN) {
return Promise.reject({
msg: "未登录,跳转登录界面",
});
}
return Promise.resolve(res.data);
},
(err) => {
wx.hideLoading();
console.log("失败响应拦截");
return Promise.reject(err);
}
);
axios.interceptor.response(
(res) => {
console.log("成功响应拦截2");
return Promise.resolve(res);
},
(err) => {
wx.hideLoading();
console.log("失败响应拦截2");
return Promise.reject(err);
}
);
axios.interceptor.response(
(res) => {
console.log("成功响应拦截3");
return Promise.resolve(res);
},
(err) => {
wx.hideLoading();
console.log("失败响应拦截3");
return Promise.reject(err);
}
);
效果:
经过今晚一阵梳理之后,现在看来一切都是那么的合理,哈哈哈哈。
wx:request也可以换成别的请求库哦!