在uniapp中封装请求接口 (带刷新token)


import { apiUrl } from '@/config/global-config.js'
import { useUserStore } from '../stores'
import { usePageRoute } from "@/composable/usePageRoute.js"

// 默认配置
const DEFAULT_CONFIG = {
	timeout: 60000,
	// showLoading: true,
	// loadingText: '加载中...'
}


// 添加刷新token的方法
const refreshToken = async () => {
	const userStore = useUserStore()
	try {
		const response = await uni.request({
			url: apiUrl + '/auth/refresh',  // 替换成你的刷新token接口
			method: 'POST',
			header: {
				'Content-Type': 'application/json',
				'Authorization': `Bearer ${userStore.token}`
			}
		})

		if (response.data.code === 200) {
			userStore.setToken(response.data.data.token)
			return true
		}
		return false
	} catch (error) {
		return false
	}
}

// 添加一个变量来存储刷新token的Promise
let isRefreshing = false
let refreshSubscribers = []

// 执行等待的请求
const onRefreshed = (token) => {
	refreshSubscribers.forEach(callback => callback(token))
	refreshSubscribers = []
}

// 添加请求到队列
const addSubscriber = (callback) => {
	refreshSubscribers.push(callback)
}


// 请求拦截器
const requestInterceptor = (config) => {
	const userStore = useUserStore()
	const token = userStore.token
	const isMapApi = /apis\.map\.qq\.com/.test(config.url)

	if (token && !isMapApi) {
		config.header.Authorization = `Bearer ${token}`
	}

	// if (config.showLoading) {
	// 	uni.showLoading({ title: config.loadingText })
	// }

	return config
}

// 响应拦截器
const responseInterceptor = async (response) => {
	const userStore = useUserStore()
	// const { code, msg, data } = response.data
	const code = response.data.code
	const msg = response.data.msg
	const data = response.data
	// const data = response.data.data
	// console.log(data,code,msg);



	switch (code) {
		case 200:
			return data
		// return Promise.resolve(data)
		case 401: {
			// 如果是刷新token的请求失败,直接登出
			 if (config.url.includes('/auth/refresh')) {
			 	await handleLogout()
			 	return Promise.reject(new Error('登录已失效'))
			 }

			 // 处理token刷新
			 if (!isRefreshing) {
			 	isRefreshing = true

			 	try {
			 		const refreshResult = await refreshToken()
			 		if (refreshResult) {
			 			const newToken = userStore.token
			 			onRefreshed(newToken)
			 			// 重试当前请求
			 			config.header.Authorization = `Bearer ${newToken}`
			 			return request(config)
			 		} else {
			 			await handleLogout()
			 			return Promise.reject(new Error('登录已失效'))
			 		}
			 	} finally {
			 		isRefreshing = false
			 	}
			 }
			 // 返回一个Promise,将请求暂存
			 return new Promise((resolve) => {
			 	addSubscriber((token) => {
			 		config.header.Authorization = `Bearer ${token}`
			 		resolve(request(config))
			 	})
			 })

			// 上面是刷新token 如果没有刷新token的接口直接登出  把上面的401代码注释 解开下面的两行注释
			//await handleLogout()
			//return Promise.reject(new Error('登录已失效'))

		}
		default:
			uni.showToast({
				icon: 'none',
				title: msg || '请求错误',
				duration: 2000
			})
			return Promise.reject(new Error(msg || '请求错误'))
	}
}

// 添加统一的登出处理方法
const handleLogout = async () => {
	const userStore = useUserStore()
	const pageRoute = usePageRoute()
	const fullPagePath = pageRoute.getCurrentFullPagePath()
	uni.setStorageSync('fullPage', fullPagePath)

	uni.$msgBox('登录已失效,请重新登录', 2000)
	userStore.clearToken()
	userStore.clearUser()
	await uni.$delay(2000)
	uni.reLaunch({ url: '/pages/login/login' })
}

// 统一请求方法
const request = (options = {}) => {
	const config = {
		...DEFAULT_CONFIG,
		...options,
		header: {
			'Content-Type': 'application/json',
			...options.header
		}
	}

	config.url = apiUrl + config.url

	// 应用请求拦截器
	const interceptedConfig = requestInterceptor(config)

	return new Promise((resolve, reject) => {
		uni.request({
			...interceptedConfig,
			success: async (res) => {
				try {
					const result = await responseInterceptor(res)
					resolve(result)
				} catch (error) {
					reject(error)
				}
			},
			fail: (error) => {
				uni.showToast({
					icon: 'none',
					title: '网络错误,请检查网络连接',
					duration: 2000
				})
				reject(error)
			},
			complete: () => {
				// if (config.showLoading) {
				// 	uni.hideLoading()
				// }
			}
		})
	})
}

// 导出请求方法
export const $get = (url, data, options = {}) => {
	return request({
		url,
		data,
		method: 'GET',
		...options
	})
}

export const $post = (url, data, options = {}) => {
	return request({
		url,
		data,
		method: 'POST',
		...options
	})
}

// 挂载到全局
uni.$get = $get
uni.$post = $post

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

有手就会:java 环境变量配置 - 包含windows、macos、linux和vscode的详细配置步骤

java 环境变量配置 本文旨在帮助用户完成Java环境变量的配置,涵盖Windows、Linux和macOS三大操作系统。对于每个系统,不仅提供了通过命令行设置环境变量的方法,还介绍了如何在VSCode中进行相应配置以启动Java项目,确保开发者能够…

Error response from daemon:

指出在尝试解析 auth.docker.io(Docker Hub 的一个域名,用于身份验证和镜像拉取)时,DNS 查询超时了。这通常意味着你的 Docker 客户端无法通过配置的 DNS 服务器(在这个案例中是 )来解析域名 解决方案&…

127.WEB渗透测试-信息收集-ARL(18)

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于: 易锦网校会员专享课 上一个内容: 这一行是对应使用的指纹 这个界面是springbot 如果存在漏洞,他的信息里面可…

字节、快手、Vidu“打野”升级,AI视频小步快跑

文|白 鸽 编|王一粟 继9月份版本更新之后,光锥智能从生数科技联合创始人兼CEO唐家渝朋友圈获悉,Vidu大模型将于本周再次进行版本升级,Vidu-1.5版本即将上线。 此版本更新方向仍是重点延伸大模型的泛化能力和主体…

分享 pdf 转 word 的免费平台

背景 找了很多 pdf 转 word 的平台都骗进去要会员,终于找到一个真正免费的,遂分享。 网址 PDF转Word转换器 - 100%免费市面上最优质的PDF转Word转换器 - 免费且易于使用。无附加水印 - 快速将PDF转成Word。https://smallpdf.com/cn/pdf-to-word

CentOS下如何安装Nginx

1、下载nginx 官方网站 http://nginx.org 下载链接:http://nginx.org/download/ 下载完成后的安装包: 2、使用解压命令进行解压 tar -zxvf nginx-1.13.7.tar.gz3、在安装所需的安装环境 安装gcc环境 yum install gcc-c安装第三方开发包 - PCRE(P…

Springboot 不同版本的配置文件怎么知道差异

起因 今天配置一个 Springboot-3.3.5 的 redis-starter,结果一直提示链接不上 redis java.net.ConnectException: Connection refused我反复对比了新项目和老项目的 redis 配置文件格式,是一模一样的! Debug 过程 配置中增加了如下配置 …

Diffusion Policy——斯坦福机器人UMI所用的扩散策略:从原理到其编码实现(含Diff-Control、ControlNet详解)

前言 本文一开始是属于此文《UMI——斯坦福刷盘机器人:从手持夹持器到动作预测Diffusion Policy(含代码解读)》的第三部分,考虑后Diffusion Policy的重要性很高,加之后续还有一系列基于其的改进工作 故独立成本文,且写的过程中 …

计算机新手练级攻略——写博客

目录 计算机新手练级攻略——写博客计算机新手写博客的好处加深知识点建立个人IP可能有额外的收入 如何写博客确定博客主题方向选择博客平台学习基础技能一定要有互动性持之以恒,克服惰性Just do it!!! 计算机新手练级攻略——写博…

哥德巴赫猜想渐行渐远

我现在的工作,表明经典分析可能出了问题,如此则连Vinogradov的三素数定理都不成立了,更别说基于L-函数方程的陈氏定理“12”了。事实上即使L-函数方程成立,由于我指出Siegel定理不成立,陈景润和张益唐的工作就不成立。…

Linux探秘坊-------1.系统核心的低语:基础指令的奥秘解析(1)

1.Linux的背景介绍 Linux 操作系统的发展历程充满了激情与创新喵~🎀 萌芽期 (1983 - 1991):Linux 的历史可追溯到 1983 年,理查德斯托曼 (Richard Stallman) 发起 GNU 计划,目标是创建一个自由软件操作系统。1987 年发…

Angular 和 Vue2.0 对比

前言 :“业精于勤,荒于嬉;行成于思,毁于随” 很久没写博客了,大多记录少进一步探查。 Angular 和 Vue2.0 对比: 一.概念 1.1 Angular 框架: 是一款由谷歌开发的开源web前端框架(核…

【Python】轻松实现机器翻译:Transformers库使用教程

轻松实现机器翻译:Transformers库使用教程 近年来,机器翻译技术飞速发展,从传统的基于规则的翻译到统计机器翻译,再到如今流行的神经网络翻译模型,尤其是基于Transformer架构的模型,翻译效果已经有了质的飞…

[2024最新] macOS 发起 Bilibili 直播(不使用 OBS)

文章目录 1、B站账号 主播认证2、开启直播3、直播设置添加素材、隐私设置指定窗口添加/删除 窗口 4、其它说明官方直播帮助中心直播工具教程 目前搜到的 macOS 直播教程都比较古早,大部分都使用 OBS,一番探索下来,发现目前已经不需要 OBS了&a…

前端 性能优化 (图片与样式篇)

文章目录 前端能够做哪些图片优化?1、减小图片体积2、图片缓存服务工作线程 (Service Workers)缓存IndexDB缓存图片LocalStorage缓存 3、图片懒加载使用 loading"lazy" 属性 4、不同分辨率下使用不同的图片5、使用webp格式的图片6、配置图片CDN7、减少图片和动图的使…

【MySQL 保姆级教学】事务的自动提交和手动提交(重点)--上(13)

目录 1. 什么是事务?2. 事务的版本支持3. 事务提交的方式3.1 事务提交方式的分类3.2 演示的准备的工作3.2.1 创建表3.2.2 MySQL的服务端和客户端3.2.3 调低事务的隔离级别 4. 手动提交4.1 手动提交的命令说明4.2 示例一4.3 示例二4.4 示例三4.5 示例四 5. 自动提交5…

C++ | Leetcode C++题解之第546题移除盒子

题目&#xff1a; 题解&#xff1a; class Solution { public:int dp[100][100][100];int removeBoxes(vector<int>& boxes) {memset(dp, 0, sizeof dp);return calculatePoints(boxes, 0, boxes.size() - 1, 0);}int calculatePoints(vector<int>& boxes…

RK3588部署ppocr流程及安装环境_笔记1

前言&#xff1a; RK3588部署ppocr流程及ubuntu安装环境 目录 一、NoMachine安装使用 二、把ubuntu系统从英文修改为中文界面 三、安装conda 没有报错说明没有问题&#xff0c;如果source的时候报错&#xff0c;查看 ​编辑 报这种错&#xff1a; 5、需要添加国内镜像源…

二分查找习题篇(下)

二分查找习题篇(下) 1.山脉数组的峰顶索引 题目描述&#xff1a; 给定一个长度为 n 的整数 山脉 数组 arr &#xff0c;其中的值递增到一个 峰值元素 然后递减。 返回峰值元素的下标。 你必须设计并实现时间复杂度为 O(log(n)) 的解决方案。 示例 1&#xff1a; 输入&#xf…

Linux学习笔记之shell快速入门及相关变量

Shell是什么 Shell是一个命令解释器&#xff0c;它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序&#xff0c;用户可以通过Shell来启动、挂起甚至编写一些程序。 Shell脚本执行方式 脚本格式要求 脚本以#!/bin/bash开头脚本需要有可执行权限 脚本的常…