当前是vue3+ts版本的封装

vue3+js版本请求封装可参考
https://www.cnblogs.com/lovejielive/p/14343619.html

token无感刷新,可自行删除 requset.ts 中 ts 相关数据恢复vue2版本

先在目录下创建 utils 和 common 这2个文件夹

img

utils 是存放工具类的,common 用来放置常用方法的

之后在utils 中创建 requset.ts 用来放置 uni.request 的请求方法,无感刷新。

1.common 文件创建 operate.ts + api.ts

主要用来放置 ,请求接口地址,一些全局请求数据,判断是否登录。

配置全局消息提示框,模拟对话框方法,方便调用

operate.ts 代码如下:


import store from '@/store/index'exportdefault{//接口
    api: function() {
let url
= '' //#ifdef MP-WEIXIN || MP-ALIPAY let version =uni.getAccountInfoSync().miniProgram.envVersion;switch(version) {case "develop": //开发预览版 url = '' break;case 'trial': //体验版 url = '' break;case 'release': //正式版 url = '' break;default: //未知,默认调用正式版 url = '' break;
}
//#endif //#ifdef H5 || APP-PLUS if (process.env.NODE_ENV === 'development') {//console.log('开发环境') url = ''}else{//console.log('生产环境') url = ''}//#endif returnurl
},
//共同请求参数 commonBeg: function() {return{
Authorization:
this.isToken(),
}
},
//是否已注册(登录状态) isLogin: function() {returnstore.state.user.hasLodin;
},
//获取用户token isToken: function() {if (store.state.user.accessToken != '') {return 'Bearer ' +store.state.user.accessToken;
}
return '';
},
//消息提示框 toast: function(options : any) {
uni.showToast({
title: options.title,
duration: options.duration
|| 2000,
icon: options.icon
|| "none"});
},
//模拟对话框 showModal: function(matter : any) {return new Promise((resolve, _reject) =>{
uni.showModal({
title: matter.title
|| '',
content: matter.content
|| '',//是否显示取消按钮,默认为 true showCancel: matter.showCancel,//取消按钮的文字,默认为"取消" cancelText: matter.cancelText || "取消",//取消按钮的文字颜色,默认为"#000000" cancelColor: matter.cancelColor || "#000000",//确定按钮的文字,默认为"确定" confirmText: matter.confirmText || "确定",/*确定按钮的文字颜色,H5平台默认为"#007aff",
微信小程序平台默认为"#576B95",
百度小程序平台默认为 "#3c76ff"
*/ //confirmColor: matter.confirmColor || '#576B95', success: (res) =>{if(res.confirm) {//console.log('用户点击确定'); resolve(res)
}
//if (res.cancel) { //console.log('用户点击取消'); //reject(res.cancel) //} }
})
})
}
}

operate.ts

api.ts 代码如下


import {
request
} from
'@/utils/requset' //手机密码登录 export const text = function(data : any) {returnrequest({
url:
"/pai/api/pai",
method:
"POST",
hideLoading:
true,
data: data,
})
}
/*使用方法: 在请求页面中调用

1.先导入本页面
import {text} from '@/common/api'

2.在methods 中 调用:
text().then((res) => {
console.log(res);
})
*/

api.ts

2.utils 中创建 requset.ts

配置
uni.request
统一请求,
uni.getNetworkType
判断当前网络状态

通过
uni.addInterceptor
拦截器,实现请求前后的数据监听(该方法只写了监听,具体逻辑项目没用到)

import route from '@/utils/routeBlocker'
路由封装-方法链接


无感刷新 token 配置,具体代码如下


import operate from "@/common/operate"import store from'@/store-ts/index'import route from'@/utils/routeBlocker'

/*解决: 类型“string | AnyObject | ArrayBuffer”上不存在属性“code”。
类型“string”上不存在属性“code”。
*/interface Codeable {
data : Object
| String |ArrayBuffer,
code : Number,
}
//请求对列 / 请求状态 let requestQueue =[],
isRefreshing
= false;

export const request
= function(param : any) {//请求参数 let url =param.url,
method
=param.method,
header
={},
data
= param.data ||{},
hideLoading
= param.hideLoading || false;//拼接完整请求地址 let requestUrl = operate.api() +url;//跨域解决 //let requestUrl = url; //console.log(requestUrl) //请求方式:GET或POST if(method) {
method
= method.toUpperCase(); //小写改为大写 if (method == "POST") {
header
={//'content-type': 'application/x-www-form-urlencoded', 'content-type': "application/json",
};
}
else{
header
={'content-type': "application/json",
};
}
}
//拼接header 登录参数 let jointHeader =Object.assign({}, header, operate.commonBeg());//用户交互:加载圈 if (!hideLoading) {
uni.showLoading({
title:
'加载中...',
mask:
true});
}
//请求-拦截器 //requestBlocker() //开始请求 return new Promise((resolve, reject) =>{//判断有无网络验证 noneNetwork().then(() =>{//请求放到promise队列,等待更新token后重新调用。 addRequestQueue(url, method, param.data, jointHeader)//更新 token flushToken().then(() =>{//执行等待的请求 onRefreshed().then(resolve).catch(reject);
})
}).
catch(() =>{//隐藏加载 if (!hideLoading) {
uni.hideLoading();
}
})
//开始请求 uni.request({
url: requestUrl,
data: data,
method: method,
header: jointHeader,
success(res) {
let data
=res.data as Codeable//code判断: 刷新令牌 if (data.code == 401) {//处理token刷新 if (!isRefreshing) {
isRefreshing
= true //请求放到promise队列,等待更新token后重新调用。 addRequestQueue(url, method, param.data, jointHeader)//更新 token flushToken().then(() =>{//执行等待的请求 onRefreshed().then(resolve).catch(reject);
})
}
return;
}
//code判断: 重新登录 if (data.code == 403) {
restartLogin()
return;
}
//将结果抛出 resolve(data)
},
//请求失败 fail: (err) =>{
operate.toast({
title:
'网络连接错误',
icon:
'loading'})//将结果抛出 reject(err)/*.catch(err=>{
console.log(err)
})
*/},//请求完成 complete() {//隐藏加载 if (!hideLoading) {
uni.hideLoading();
}
}
})
})
}
//执行等待的请求 const onRefreshed = () =>{return new Promise((resolve, reject) =>{
let item
=requestQueue.shift();//console.warn('执行等待的请求', item); request({
url: item.url,
method: item.method,
hideLoading:
true,
data: item.data,
}).then(resolve).
catch(reject)
});
}
//添加请求到队列 const addRequestQueue = (url : string, method : object, data : object, header : object) =>{
requestQueue.push({
url,
method,
data,
header
})
}
/**
* @description: 登录刷新 token 请求接口
* @return
*/export const flushToken= function() {return new Promise((resolve, errs) =>{
uni.request({
url: operate.api()
+ '/app-api/refresh-token-刷新接口地址',
method:
'POST',
header: {
'Content-Type': 'application/json'},
data: {
refreshToken: store.getters[
'flushToken'],
},
success(res) {
//console.warn('刷新令牌', res.data); let data =res.data as anyif (data.code == 0) {//登录刷新 store.commit("user/REFRESH_TOKEN", {
accessToken: data.data.accessToken,
refreshToken: data.data.refreshToken
});

resolve(
'刷新令牌成功')return}//登录 失效 if (data.code == 401) {
operate.showModal({
title:
'您的登陆已过期',
confirmText:
'重新登录',
showCancel:
false,
}).then((_res)
=>{//清除登录信息 store.commit('user/LOG_OUT');//去登录页 restartLogin(false)
})
}
},
fail: (err)
=>{
console.error(
'刷新令牌失败', err);
errs(err)
},
complete() {
isRefreshing
= false}
})
})
}
/**
* @description: 请求-拦截器
* @return
* 通过拦截器,实现请求前后的数据监听
*/ //const requestBlocker = function () {//uni.addInterceptor('request', {//invoke(args) {//console.log("求前后的数据监听",args);//}//})//} /**
* @description: 判断有无网络验证
* @return
*/const noneNetwork= function() {return new Promise((resolve, reject) =>{
uni.getNetworkType({
success(res) {
if (res.networkType == 'none') {
uni.showModal({
title:
'没有网络',
content:
'请检查您的网络',
showCancel:
false,
success: (_res)
=>{
resolve(
"无网络确定-返回")
}
});
}
},
complete() {
reject(
'取消-加载圈')
}
})
})
}
/**
* @description: 重新登录(统一方法)
* @return
*/const restartLogin= function (toastShow = true) {if(toastShow) {
operate.toast({
title:
"登录超时!请重新登录"})
}
setTimeout(()
=>{
route({
url:
'/pages/logIn/logIn',
type:
"navigateTo",
login:
false,
})
},
500)
}

requset.ts

缺点:在多个请求同时进行,会出现多次调用(刷新token)的情况。

当前使用
isRefreshing
判断请求刷新转态,没结束不能在调用刷新接口,对于复数请求,还是会多次请求刷新。

下图测试为,同时请求4个接口

项目地址:
https://gitee.com/jielov/uni-app-tabbar

标签: none

添加新评论