uniapp无感刷新token实现过程

news2024/12/25 23:14:18

路漫漫其修远兮,前端道路逐渐迷茫,时隔好久好久终于想起了我还有一个小博客,最近在一直在弄uniapp,属实有被恶心到,但也至少会用了,最近实现了一个比较通用的功能,就是无感刷新token,但在过程中发现一个问题就是token也刷新,接口也重新请求了,但页面就是没有刷新

上面问题归根结底还是自己对于promise、async、await等知识理解不够深刻导致的,先看看无感刷新token怎么实现的吧!废话不多说上代码(代码都有注释):

import Request from './request' // 对uniapp.request的简易封装
import { getRefreshToken } from '@/common/api/apis.js' // 刷新token接口
const http = new Request()

let isRefresh = false // 是否处于刷新token状态中
let fetchApis = [] // 失效后同时发送请求的容器
let refreshCount = 0 // 限制无感刷新的最大次数
function onFetch(newToken) {
	refreshCount += 1
	if (refreshCount === 3) {
		refreshCount = 0
		fetchApis = []
		return Promise.reject()
	}
	fetchApis.forEach(callback => {
		callback(newToken)
	})
	// 清空缓存接口
	fetchApis = []
	return Promise.resolve()
}

// 响应拦截(主要看error,因为token过期一般你们后端接口都是返回401/402,在对应case下处理刷新token逻辑即可)
http.interceptor.response((response) => {
	/* 请求之后拦截器 */
    if (response.config.loading) {
      uni.hideLoading()
    }
    // 请求成功但接口返回的错误处理
    if (response.data.statusCode && +response.data.statusCode !== 200) {
      if (!response.config.needPromise) {
        console.log('error', response)
        uni.showModal({
          title: '提示',
          content: response.data.message,
          showCancel: false,
          confirmText: '知道了'
        })
        // 中断
        return new Promise(() => {})
      } else {
        // reject Promise
        return Promise.reject(response.data)
      }
    }
    return response
}, (error) => {
	// 请求错误做点什么
	const token = uni.getStorageSync('token')
    const refreshToken = uni.getStorageSync('refreshToken')
    // DESC: 不需要做无感刷新的白名单接口
    const whiteFetchApi = ['/dealersystem/jwtLogin', '/dealersystem/smsLogin', '/sso2/login', '/dealersystem/isLogin']
    switch (error.statusCode) {
		// token过期处理,实现无感刷新
	  	case 401:
	  	case 402:
		  	// 如果登录过,token过期走refreshToken逻辑
		    if (token && !whiteFetchApi.includes(error.config.url)) {
				if (!isRefreshing) {
					isRefreshing = true
					getRefreshToken({ refreshToken }).then(res => {
						let newToken = res.data
						onTokenFetched(newToken).then(res => {}).catch(err => {
							// 超过循环次数时,回到登录页,这里可以添加你执行退出登录的逻辑
							uni.showToast({ title: '登录失效,请重新登录', icon: 'error' })
							setTimeout(() => {
								uni.reLaunch({url: '/pages/login/login'})
							}, 1500)
						})
					}).catch(err => {
						// refreshToken接口报错,证明refreshToken也过期了,那没办法啦重新登录呗
						uni.showToast({ title: '登录失效,请重新登录', icon: 'error' })
			            setTimeout(() => {
			              uni.reLaunch({ url: '/pages/login/login' })
			            }, 1500)
					}).finally(() => { isRefreshing = false })
				}
				return new Promise((resolve) => { // 此处的promise很关键,就是确保你的接口返回值在此处resolve,以便
		        	addFetchApi((newToken) => {
		         	 	error.config.header.token = newToken
		          		resolve(http.request(error.config))
		        	})
		      	})
			} else {
				// 没有登录过,直接输入链接访问的情况
				if (whiteFetchApi.includes(error.config.url)) {
					return Promise.reject(error.data)
				}
		      	uni.showToast({ title: '您未登录,请前往登录', icon: 'error' })
			    setTimeout(() => {
		        	uni.reLaunch({ url: '/pages/login/login' })
		      	}, 1500)
		      	return Promise.reject(error.data)
			}
		default:
		    errorMsg = error.data.message || ''
		    break
		}
		uni.showModal({
		  title: '提示',
		  content: errorMsg,
		  showCancel: false,
		  confirmText: '知道了'
		})
    	return Promise.reject(error.data)
	})

业务侧列表页请求接口:(我的问题就在于调用接口后,下方的代码不执行,导致页面数据不更新
也就是说该语句没有resolve回结果在这里插入图片描述
在这里插入图片描述

那么,怎么排查问题呢,首先先复现问题:
1、token我在localStorage缓存了一份,可以在谷歌浏览器中更改token,模拟token过期
在这里插入图片描述
2、触发如上项目列表的分页接口:
在这里插入图片描述
可以看到已经触发了刷新token接口,并且重新请求上次失败的列表接口,无感刷新token逻辑已经正常,但为什么列表接口请求成功,还一直loading没关闭捏,就是因为后续代码未执行,await接口的返回没有成功resolve

3、排查await的列表接口为何没有成功resolve
(1) 列表页
在这里插入图片描述
(2) 接口配置页
在这里插入图片描述
(3) 接口全局配置文件api/index.js,就是在此处将接口返回数据resolve回来,此时再看http.request方法
在这里插入图片描述
(4) uni.request封装文件request.js,发现问题所在,当接口请求失败时,这里直接reject了,那么真相大白;
在这里插入图片描述

熟悉promise的话,应该知道:

  • resolve一个promise相当于返回一个新的promise
  • await语句要成功获取到值时,该promise必须是resolve的fulfilled状态,如若未对await语句进行try catch处理,那么会阻止后续代码的执行
    在这里插入图片描述
    所以怎么改呢,将上述request.js文件的reject替换成resolve即可解决啦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1113496.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何下载和安装 Linux Red Hat 9.0安装包

【微|信|公|众|号:厦门微思网络】 官网: www.xmws.cn 【限时优惠】RHCE9.0培训考证-红帽官方授权中心-CSDN博客通过这门课程,您将能够更好的理解企业级需求和解决方案,提升您的战略思 维和决策能力并助力您为企业升级使用新的技…

【C++】引用之带你“消除”C语言版数据结构教材的一些困惑(虽然是C++的内容,但是强烈建议正在学习数据结构的同学点进来看看)

👀樊梓慕:个人主页 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》 🌝每一个不曾起舞的日子,都是对生命的辜负 目录 前言 引用的概念 引用的特性 引用的使用场…

Django实现音乐网站 ⒇

使用Python Django框架做一个音乐网站, 本篇音乐播放器-添加播放音乐功能实现。 目录 创建播放器数据表 设置表结构 执行创建表 命令 执行 数据表结构 添加单个歌曲 创建路由 加入播放器视图 模板处理 基类方法 子页面调用 优化弹窗 加入layui文件 基…

DPDK收发包流程分析

一、 前言 DPDK是intel工程师开发的一款用来快速处理数据包的框架,最初的目的是为了证明传统网络数据包处理性能低不是intel处理器导致的,而是传统数据的处理流程导致,后来随着dpdk的开源及其生态的快速发展,dpdk成为了高性能网络数据处理的优秀框架。本篇文章主要介绍DPDK…

游戏动态库缺失

缺哪个动态库就搜哪个,再下载下来。 百度网盘:链接:https://pan.baidu.com/s/1TlxLtL3hg_iCCvtCzT7bXw 提取码:8888 文件下载完之后要放到指定的位置 C:\Windows\System32

怎么在爬虫中使用ip代理服务器,爬虫代理IP的好处有哪些?

随着互联网的快速发展,网络爬虫已经成为数据采集、分析和整理的重要工具。然而,随着网络技术的不断发展,许多网站都会采取反爬虫措施,以避免数据被恶意获取。在这种情况下,代理IP服务器就成为了爬虫们的必本备文工将具…

Flink学习---15、FlinkCDC(CDC介绍、案例实操)

星光下的赶路人star的个人主页 未来总是藏在迷雾中让人胆怯,但当你踏入其中,便会云开雾散 文章目录 1、CDC简介1.1 什么是CDC1.2 CDC的种类1.3 Flink-CDC 2、FlinkCDC案例实操2.1 开启MySQL Binlog并重启MySQL2.2 FlinkSQL方式的应用2.2.1 导入依赖2.2.2…

jadx的使用

这篇文章主要介绍下jadx的使用。 1:下载安装 开源地址如下: https://github.com/skylot/jadx 当前最新的版本是1.4.7: https://github.com/skylot/jadx/releases/tag/v1.4.7 2:使用jadx mac/linux 使用jadx-gui.windows使用…

2023年中国光模块行业研究报告

第一章 行业概况 1.1 行业简介 光模块行业是光纤通信技术发展的重要组成部分,作为连接光纤通信网络的基础设备,光模块为数据传输提供了必要的硬件支持。光模块是光纤通信系统核心器件之一,它包括多种模块类别,例如光接收模块、光…

Random与random的区别

Random与random的区别 前言一、Rondom二、rondom三、使用Rondom的好处 前言 Rondom和raodom都可以表示随机数,下面是详细讲解 提示:以下是本篇文章正文内容,下面案例可供参考 一、Rondom Rondom是Java中的一个类,若需要生成随机…

在URP管线中添加ShaderMaterial自定义GUI的方法

编写GUI面板 1. 新建GUI子面板 using UnityEngine; using UnityEngine.Rendering;namespace UnityEditor.Rendering.Universal.ShaderGUI {internal class CP_XXXOutLineGUI{public static class Styles{}public struct LitProperties{public LitProperties(MaterialProperty…

速卖通,国际站测评补单用什么环境,买家账号不会被风控,F号

我们做自养号测评、补单首先要解决的就是安全性的问题,如果安全性解决的不了的话,其他的都不要再提了。目前我们的成号率可以稳定在9.8成以上,基本上0砍单封号 市面上的环境有: 1.虚拟机V2;三四年前的环境方案了&…

6. 加载栅格(raster)图层

文章目录 前言加载栅格(raster)图层gdalGeoTiffQGis导入tif代码添加 GeoPackageQGis导入代码导入 wms在线高德影像地图QGis添加在线高德影像代码添加 离线高德影像地图瓦片原理服务描述XML文件QGis导入离线地图代码导入 前言 本章讲述使用qgis c Api加载栅格地图数据并显示。 …

卡通人像制作就是这么简单

1、打开提示词生成器。 Prompt Generatorhttps://remaker.ai/userspace/prompt-generator/2、按下面截图设置。 3、复制英文提示。 4、打开画图链接。 https://poe.com/chat/https://poe.com/chat/ 5、输入提示词,按回车。 female,wide eyes,lipstick,fox ears,b…

解决一则诡异的javascript函数不执行的问题

有个vue 音乐播放器项目,由于之前腾讯的搜索接口没法用了,于是改成了别家的搜索接口。 但是由于返回数据结构不一样,代码重构的工作量还是挺大的:包括数据请求,数据处理,dom渲染,处理逻辑都进行…

C++算法:二叉树的序列化与反序列化

#题目 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。 请设计一个算法来实现二叉树的序列化与反序列化。…

golang的json转pb验证

基于这篇文章的最后一个代码进行验证。 https://blog.csdn.net/mijichui2153/article/details/133894403?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22133894403%22%2C%22source%22%3A%22mijichui2153%22%7D 1、准备 &…

gs_moment

ps:仅共学习,自用。

OpenGL —— 2.7、绘制多个自旋转的贴图正方体(附源码,glfw+glad)

源码效果 C源码 纹理图片 需下载stb_image.h这个解码图片的库,该库只有一个头文件。 具体代码: vertexShader.glsl #version 330 corelayout(location 0) in vec3 aPos; layout(location 1) in vec2 aUV;out vec2 outUV;uniform mat4 _modelMatrix; …

抽象数据库

在刚刚的文章中,完成了无范式到三级范式的过程 : 遵循原子性。即,表中字段的数据,不可以再拆分。 在满足第一范式的情况下,遵循唯一性,消除部分依赖。即,表中任意一个主键或任意一组联合主键&#xff0c…