uniapp请求封装-token无感刷新
当前是vue3+ts版本的封装
vue3+js版本请求封装可参考 https://www.cnblogs.com/lovejielive/p/14343619.html
token无感刷新,可自行删除 requset.ts 中 ts 相关数据恢复vue2版本
先在目录下创建 utils 和 common 这2个文件夹
utils 是存放工具类的,common 用来放置常用方法的
之后在utils 中创建 requset.ts 用来放置 uni.request 的请求方法,无感刷新。
1.common 文件创建 operate.ts + api.ts
主要用来放置 ,请求接口地址,一些全局请求数据,判断是否登录。
配置全局消息提示框,模拟对话框方法,方便调用
operate.ts 代码如下:


import store from '@/store/index' export default {
//接口
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 return url
}, //共同请求参数
commonBeg: function () {
return {
Authorization: this.isToken(),
}
}, //是否已注册(登录状态)
isLogin: function () {
return store.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) {
return request({
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 any if (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
uniapp请求封装-token无感刷新的更多相关文章
- 无感刷新 Token
什么是JWT JWT是全称是JSON WEB TOKEN,是一个开放标准,用于将各方数据信息作为JSON格式进行对象传递,可以对数据进行可选的数字加密,可使用RSA或ECDSA进行公钥/私钥签名. 使 ...
- Spring Cloud实战 | 最八篇:Spring Cloud +Spring Security OAuth2+ Axios前后端分离模式下无感刷新实现JWT续期
一. 前言 记得上一篇Spring Cloud的文章关于如何使JWT失效进行了理论结合代码实践的说明,想当然的以为那篇会是基于Spring Cloud统一认证架构系列的最终篇.但关于JWT另外还有一个 ...
- axios实现无感刷新
前言 最近在做需求的时候,涉及到登录token,产品提出一个问题:能不能让token过期时间长一点,我频繁的要去登录. 前端:后端,你能不能把token 过期时间设置的长一点. 后端:可以,但是那样做 ...
- 基于OAuth2.0的token无感知刷新
目前手头的vue项目关于权限一块有一个需求,其实架构师很早就要求我做了,但是由于这个紧急程度不是很高,最近临近项目上线,我才想起,于是赶紧补上这个功能.这个项目是基于OAuth2.0认证,需要在每个请 ...
- 请求时token过期自动刷新token
1.在开发过程中,我们都会接触到token,token的作用是什么呢?主要的作用就是为了安全,用户登陆时,服务器会随机生成一个有时效性的token,用户的每一次请求都需要携带上token,证明其请求的 ...
- uni-app 请求封装
1.创建一个http.js const baseUrl = 'http://192.168.1.188:8080'; const httpRequest = (opts, data) => ...
- Axios 网络请求组件封装 (鉴权、刷新、拦截)
一.前言 注意:本教程需要你对axios有一定的了解,不适用于小白(只能借鉴,希望你能自己动手),注释都写的很清楚.此封装并非完整版,已进行部分删减修改操作,但仍然适用于大部分业务场景,如果不适用于你 ...
- Flutter 实际开发常用工具类(全局提示,请求封装,token缓存,验证码倒计时、常用窗帘动画及布局)
介绍: 一星期从入门到实际开发经验分享及总结 代码传送门github Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面.未来App开发 ...
- drf:restful概念,类继承关系,drf请求封装,drf请求流程,版本控制组件,认证组件(token),权限组件
1.restful规范 resfful规范的概念最重要: 是一套规范,规则,用于程序之间进行数据交换的约定. 他规定了一些协议,对我们感受最直接的就是,以前写增删改查的时候需要些四个视图寒素,rest ...
- uniapp 基于 flyio 的 http 请求封装
之前写请求都是用别人封装好的,直接 import request 完事,自己第一次写还是一头雾水,学习了一波搞清楚了些,可以写简单的封装了. 首先要搞清楚为什么封装请求,同其他的封装一样,我们把不同请 ...
随机推荐
- 函数(C语言)
目录 1. 函数的概念 2. 库函数 2.1 标准库和头文件 2.2 库函数的使用方法 3. 自定义函数 3.1 函数的语法形式 3.2 函数的举例 4. 形参和实参 4.1 实参 4.2 形参 4. ...
- 《HelloGitHub》第 103 期
兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 HelloGitHub 分享 GitHub 上有趣.入门级的开源项目. github.com/521xueweihan/HelloG ...
- 掌控物体运动艺术:图扑 Easing 函数实践应用
现如今,前端开发除了构建功能性的网站和应用程序外,还需要创建具有吸引力且尤为流畅交互的用户界面,其中动画技术在其中发挥着至关重要的作用.在数字孪生领域,动画的应用显得尤为重要.数字孪生技术通过精确模拟 ...
- MyBatis-Plus条件构造器:构建安全、高效的数据库查询
一.关于条件构造器(Wrapper) 1.1 简介 MyBatis-Plus 提供了一套强大的条件构造器(Wrapper),用于构建复杂的数据库查询条件.Wrapper 类允许开发者以链式调用的方式构 ...
- 2.16 Linux挂载详解
前面讲过,Linux 系统中"一切皆文件",所有文件都放置在以根目录为树根的树形目录结构中.在 Linux 看来,任何硬件设备也都是文件,它们各有自己的一套文件系统(文件目录结构) ...
- markdown小小白常用语法
第一次用vscode写笔记去同步Cnblog,不知道写啥就记点常用的md语法吧 1. 标题怎么写? 利用"#" + " " 即可实现第几节标题(其中'/',表转 ...
- jQuery.validator验证无效的可能原因
最近用jQuery.validator做表单的前端验证,却发现验证规则都无效.最后发现以下原因会导致校验无效 1.jquery.min.js重复引用. 2.js中有bug存在. 3.<input ...
- Solr 学习(5) —- Solr查询语法和参数
1.查询地址 建立好solr的索引后,可以通过管理界面进行查询.http://127.0.0.1:8983/solr/admin/form.jsp 要尝试多个查询方法的话,可以进入full inter ...
- 如何使用Python编写一个Lisp解释器
原文出处: Peter Norvig 译文出处: jnjc(@jnjcc) 本文有两个目的: 一是讲述实现计算机语言解释器的通用方法,另外一点,着重展示如何使用Python来实现Lisp方言Sch ...
- Java深度历险(一)——Java字节代码的操纵
[编者按]Java作为业界应用最为广泛的语言之一,深得众多软件厂商和开发者的推崇,更是被包括Oracle在内的众多JCP成员积极地推动发展.但是对于Java语言的深度理解和运用,毕竟是很少会有人涉及的 ...