当前是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无感刷新的更多相关文章

  1. 无感刷新 Token

    什么是JWT JWT是全称是JSON WEB TOKEN,是一个开放标准,用于将各方数据信息作为JSON格式进行对象传递,可以对数据进行可选的数字加密,可使用RSA或ECDSA进行公钥/私钥签名. 使 ...

  2. Spring Cloud实战 | 最八篇:Spring Cloud +Spring Security OAuth2+ Axios前后端分离模式下无感刷新实现JWT续期

    一. 前言 记得上一篇Spring Cloud的文章关于如何使JWT失效进行了理论结合代码实践的说明,想当然的以为那篇会是基于Spring Cloud统一认证架构系列的最终篇.但关于JWT另外还有一个 ...

  3. axios实现无感刷新

    前言 最近在做需求的时候,涉及到登录token,产品提出一个问题:能不能让token过期时间长一点,我频繁的要去登录. 前端:后端,你能不能把token 过期时间设置的长一点. 后端:可以,但是那样做 ...

  4. 基于OAuth2.0的token无感知刷新

    目前手头的vue项目关于权限一块有一个需求,其实架构师很早就要求我做了,但是由于这个紧急程度不是很高,最近临近项目上线,我才想起,于是赶紧补上这个功能.这个项目是基于OAuth2.0认证,需要在每个请 ...

  5. 请求时token过期自动刷新token

    1.在开发过程中,我们都会接触到token,token的作用是什么呢?主要的作用就是为了安全,用户登陆时,服务器会随机生成一个有时效性的token,用户的每一次请求都需要携带上token,证明其请求的 ...

  6. uni-app 请求封装

    1.创建一个http.js ​ const baseUrl = 'http://192.168.1.188:8080'; const httpRequest = (opts, data) => ...

  7. Axios 网络请求组件封装 (鉴权、刷新、拦截)

    一.前言 注意:本教程需要你对axios有一定的了解,不适用于小白(只能借鉴,希望你能自己动手),注释都写的很清楚.此封装并非完整版,已进行部分删减修改操作,但仍然适用于大部分业务场景,如果不适用于你 ...

  8. Flutter 实际开发常用工具类(全局提示,请求封装,token缓存,验证码倒计时、常用窗帘动画及布局)

    介绍: 一星期从入门到实际开发经验分享及总结           代码传送门github Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面.未来App开发 ...

  9. drf:restful概念,类继承关系,drf请求封装,drf请求流程,版本控制组件,认证组件(token),权限组件

    1.restful规范 resfful规范的概念最重要: 是一套规范,规则,用于程序之间进行数据交换的约定. 他规定了一些协议,对我们感受最直接的就是,以前写增删改查的时候需要些四个视图寒素,rest ...

  10. uniapp 基于 flyio 的 http 请求封装

    之前写请求都是用别人封装好的,直接 import request 完事,自己第一次写还是一头雾水,学习了一波搞清楚了些,可以写简单的封装了. 首先要搞清楚为什么封装请求,同其他的封装一样,我们把不同请 ...

随机推荐

  1. MVC PHP架构 博客论坛实现全过程

    目录 1. MVC的历史 1.1 优点与缺点 1.1.1 优点 1.1.2 缺点 2. 个人博客论坛的MVC实现 2.1 前言 2.2 web代码结构 框架 2.2.1 web应用发展 2.2.2 C ...

  2. python面向对象复习

    1.类的语法 # 类的语法 # 定义类 class Dog(object): # 类的属性或者类变量,一般是公共属性,存在类的内存空间,所有实例对象共享 d_type = "京巴" ...

  3. linux不常用命令

    1.查看进程的内存资源占用 [root@abdi1 elasticsearch]# pidstat -r -p 1791 1 Linux 3.10.0-514.el7.x86_64 (abdi1) 0 ...

  4. 2024Java编程思想第四版(完整中文高清pdf)

    前言 再也不用担心书荒咯~~ 目录 Java编程思想第四版完整中文高清版(免费)***

  5. [离线计算-Spark|Hive] 数据近实时同步数仓方案设计

    背景 最近阅读了大量关于hudi相关文章, 下面结合对Hudi的调研, 设计一套技术方案用于支持 MySQL数据CDC同步至数仓中,避免繁琐的ETL流程,借助Hudi的upsert, delete 能 ...

  6. 【转载】scipy.stats.norm.ppf —— 分位点函数(CDF的逆)(也被用作“标准偏差乘数”)

    原文地址: https://www.cnblogs.com/jiangkejie/p/15292260.html scipy.stats.norm.ppf() 分位点函数(CDF的逆)(也被用作&qu ...

  7. MNN框架在WIN10上的部署

    一.为什么要做 刚进公司,实习期反正主管要求什么我就做什么....自己反正也比较感兴趣,故开始查看官方文档.下述的一切都是基于官方提供的"语雀文档"内的指令进行的,会对自己部署MN ...

  8. html中input标签放入小图标

    直接上代码 <style type="text/css"> *{ margin: 0; padding: 0; } .box{ width: 200px; positi ...

  9. 静态分析工具及使用总结(二)CheckStyle

    这里主要介绍三种开源的工具,PMD.CheckStyle和FindBugs,着重是在Ant里的调用,据说商业软件JTest也是著名的代码分析工具,哈哈,要花钱的没有用过. Checkstyle (ht ...

  10. 解读vue的webpack.base.conf.js配置

    'use strict' // 引入nodejs路径模块 const path = require('path') // 引入utils工具模块,utils主要用来处理css-loader和vue-s ...