当前位置: 首页 > news >正文

【前端开发】小程序无感登录验证

概述

封装的网络请求库,主要用于处理 API 请求并支持自动处理 token 过期 和 token 刷新,适用于需要身份验证的应用场景,特别是在移动端中。

主要功能

  1. 自动附加 Token

在每个请求中自动附加 Authorization 头部,使用存储的 accessToken。如果某个请求不需要 Token,则可以通过设置 isToken: false 来排除。

  1. Token 过期自动刷新
  • 当请求返回提示 accessToken 过期时,自动尝试使用 refreshToken 刷新 accessToken
  • 在刷新过程中,新的请求会被放入一个队列中,等到 refreshToken 成功后再依次重试
  1. 请求重试机制
  • 当 accessToken 刷新成功后,队列中的所有待处理请求都会自动重发
  • 如果 refreshToken 刷新失败,跳转到登录页面,让用户重新登录。
  1. 统一的请求和响应处理
  • 请求的 Content-Type 和 Accept 头部统一设置
  • 统一处理服务器返回的状态码,若返回 200 且不含 ErrType: -10011,则正常返回数据,否则进行相关的错误处理

代码概览

  1. refreshToken 函数
  • 用于发送请求以刷新 accessToken,通过 refreshToken 获取新的 accessToken,并保存在本地
  • 若成功,返回新的 accessToken;若失败,返回错误信息。
  1. request 函数
  • 封装了 uni.request 请求方法,提供了 GET、POST 请求支持。
    检查是否有有效的 accessToken,如果有,自动将其附加到请求头的 Authorization 中
  • 如果请求参数中包含 params,则自动将其转换为查询字符串附加到 URL 中
  • 在请求成功时,判断返回数据的 ErrType 是否为 -10011(表示 accessToken 过期),若过期,则调用 handleTokenExpiration 函数刷新 Token
  1. handleTokenExpiration 函数
  • 处理 accessToken 过期的逻辑,避免在刷新 Token 的过程中发起多次刷新请求
  • 如果当前没有刷新请求正在进行,则调用 refreshToken 函数尝试刷新 Token,并将待重试的请求保存在队列中
  • 如果刷新 Token 成功,则重试队列中的请求,重新发送
  • 如果刷新 Token 失败,清空队列并跳转到登录页面
  1. isRefreshing 和 requestQueue
  • isRefreshing 用于确保只有一个刷新请求在进行,避免并发刷新 Token 的情况
  • requestQueue 用于存储等待 Token 刷新完成后的请求,确保刷新完成后再逐一处理这些请求

工作流程

  • 用户首次登录时,后端会返回 accessToken 和 refreshToken
  • 后续的 API 请求都会自动附带 accessToken
  • 当 accessToken 过期时,后端返回 ErrType: -10011,触发 handleTokenExpiration
  • handleTokenExpiration 检查是否正在进行刷新操作,如果没有,则开始刷新并保存待重试的请求
  • 刷新完成后,重试这些请求,确保请求使用最新的 accessToken

Request.js

import store from "@/store";
import config from "@/common/config";
import { getToken, getRefreshToken, setToken } from "@/common/auth";
import { tansParams } from "@/common/index";let timeout = 10000;
const baseUrl = config.baseUrl;const refreshToken = () => {return new Promise((resolve, reject) => {uni.request({method: "post",url: `${baseUrl}/auth/refresh`,data: { refreshToken: getRefreshToken() },header: { "Content-Type": "application/json" },}).then((response) => {if (response.statusCode === 200 && response.data.accessToken) {setToken(response.data.accessToken);resolve(response.data.accessToken);} else {reject("刷新令牌失败");}}).catch((error) => {reject(error);});});
};const request = (config) => {const isToken = (config.headers || {}).isToken === false;config.header = config.header || {};if (getToken() && !isToken) {config.header["Authorization"] = "Bearer " + getToken();}if (config.params) {let url = config.url + "?" + tansParams(config.params);url = url.slice(0, -1);config.url = url;}config.header["Content-Type"] ="application/x-www-form-urlencoded; charset=UTF-8";config.header["Accept"] = "application/json, text/javascript, */*; q=0.01";return new Promise((resolve, reject) => {uni.request({method: config.method || "get",timeout: config.timeout || timeout,url: config.baseUrl || baseUrl + config.url,data: config.data,header: config.header,dataType: "json",}).then((response) => {if (response.statusCode === 200) {//登录过期if (response.data.ErrType == "-10011") {// Access Token 过期handleTokenExpiration(config, resolve, reject);} else {resolve(response.data);}} else {reject("服务器连接异常");}}).catch((error) => {reject(error);});});
};let isRefreshing = false; // 防止多次刷新
let requestQueue = []; // 队列存储待重试的请求const handleTokenExpiration = (config, resolve, reject) => {if (!isRefreshing) {isRefreshing = true; // 开始刷新refreshToken().then((newToken) => {isRefreshing = false;// 刷新成功后,重试队列中的请求requestQueue.forEach((callback) => callback(newToken));requestQueue = []; // 清空队列// 重新发送当前请求resolve(request({...config,header: {...config.header,Authorization: "Bearer " + newToken,},}));}).catch((error) => {isRefreshing = false;requestQueue = []; // 清空队列// 刷新失败,跳转到登录页面uni.reLaunch({url: "/pages/login",});reject("登录已过期,请重新登录");});} else {// 如果已经在刷新,将请求加入队列requestQueue.push((newToken) => {resolve(request({...config,header: {...config.header,Authorization: "Bearer " + newToken,},}));});}
};export default request;

相关文章:

【前端开发】小程序无感登录验证

概述 封装的网络请求库,主要用于处理 API 请求并支持自动处理 token 过期 和 token 刷新,适用于需要身份验证的应用场景,特别是在移动端中。 主要功能 自动附加 Token 在每个请求中自动附加 Authorization 头部,使用存储的 acces…...

Flink常见面试题

1、Flink 的四大特征(基石) 2、Flink 中都有哪些 Source,哪些 Sink,哪些算子(方法) 预定义Source 基于本地集合的source(Collection-based-source) 基于文件的source(…...

spark同步mysql数据到sqlserver

使用Apache Spark将数据从MySQL同步到SQL Server是一个常见的ETL(Extract, Transform, Load)任务。这里提供一个基本的步骤指南,以及一些代码示例来帮助你完成这项工作。 ### 前提条件 1. **安装Spark**:确保你的环境中已经安装了…...

Python Web 开发:FastAPI 基本概念与应用

Python Web 开发:FastAPI 基本概念与应用 目录 ✨ 1. FastAPI 路由(定义请求路径)🚀 2. HTTP 请求方法(GET、POST、PUT、DELETE)🔑 3. 参数类型(路径参数、查询参数、请求体&#…...

Linux设置开启启动脚本

1.问题 每次启动虚拟机需要手动启动网络,不然没有enss33选项 需要启动 /mnt/hgfs/dft_shared/init_env/initaial_env.sh 文件 2.解决方案 2.1 修改/etc/rc.d/rc.local 文件 /etc/rc.d/rc.local 文件会在 Linux 系统各项服务都启动完毕之后再被运行。所以你想要…...

go并发设计模式runner模式

go并发设计模式runner模式 真正运行的程序不可能是单线程运行的,go语言中最值得骄傲的就是CSP模型了,可以说go语言是CSP模型的实现。 假设现在有一个程序需要实现,这个程序有以下要求: 程序可以在分配的时间内完成工作&#xff0…...

nn.RNN解析

以下是RNN的计算公式,t时刻的隐藏状态H(t)等于前一时刻隐藏状态H(t-1)乘以参数矩阵,再加t时刻的输入x(t)乘以参数矩阵,最后再通过激活函数,等到t时刻隐藏状态。 下图是输出input和初始化的隐藏状态,当参数batch_first True时候&…...

How to monitor Spring Boot apps with the AppDynamics Java Agent

本文介绍如何使用 AppDynamics Java 代理监视 Azure Spring Apps 中的 Spring Boot 应用程序。 使用 AppDynamics Java 代理可以: 监视应用程序使用环境变量配置 AppDynamics Java 代理 在 AppDynamics 仪表板中检查所有监视数据 How to monitor Spring Boot app…...

Linux学习笔记12 systemd的其他命令

前文已经介绍了systemd在系统初始化中起到的作用和服务的管理和配置。这里补充一下systemd的其他工具和系统进程的管理 前文 Linux学习笔记10 系统启动初始化,服务和进程管理(上)-CSDN博客 Linux学习笔记11 系统启动初始化,服务…...

NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测,含优化前后对比

NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测,含优化前后对比 目录 NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测,含优化前后对比预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介…...

【分布式】分布式缓存

一、什么是分布式缓存 分布式缓存是一种将缓存数据存储在多个节点上的缓存方案。它通过将数据分散存储在多个节点的内存中,以提高系统的读取性能、降低数据库压力和提高系统可扩展性。 二、分布式缓存的优点 优点明细提高性能:分布式缓存可以将数据缓…...

深度学习中的迁移学习:应用与实践

引言 在深度学习领域,迁移学习(Transfer Learning)是一个非常强大且日益流行的概念,它通过将从一个任务中学到的知识应用于另一个任务,能够显著加快模型训练速度并提高其泛化能力。迁移学习在许多实际应用中都得到了广…...

28.UE5实现对话系统

目录 1.对话结构的设计(重点) 2.NPC对话接口的实现 2.1创建类型为pawn的蓝图 2.2创建对话接口 3.对话组件的创建 4.对话的UI设计 4.1UI_对话内容 4.2UI_对话选项 4.3UI_对话选项框 5.对话组件的逻辑实现 通过组件蓝图,也就是下图中的…...

Redis中的分布式锁(步步为营)

分布式锁 概述 分布式锁指的是,所有服务中的所有线程都去获取同一把锁,但只有一个线程可以成功的获得锁,其他没有获得锁的线程必须全部等待,直到持有锁的线程释放锁。 分布式锁是可以跨越多个实例,多个进程的锁 分布…...

CentOS 7安装mysql+JDK+Tomcat完成流程

一.安装mysql 即使是新的linux服务器,也要先验证是否有mysql已经安装,如果有进行卸载原版本,一定要确认是否mysql已不再使用 原安装情况(直接执行命令即可) whereis mysql rpm -qa | grep -i mysql rpm -e perl-DBD-M…...

C++笔记之不同框架中事件循环的核心函数:io_run()、ros_spin()、app_exec()

C笔记之不同框架中事件循环的核心函数:io_run()、ros_spin()、app_exec() code review! 参考笔记 1.qt-C笔记之使用QtConcurrent异步地执行槽函数中的内容,使其不阻塞主界面 2.qt-C笔记之QThread使用 3.qt-C笔记之多线程架构模式:事件信号监…...

C++异常处理

目录 一、异常的概念 二、异常的使用 (1)异常的抛出和捕获 (2)异常的重新抛出 (3)异常安全 (4)异常规范 三、自定义异常体系 四、c标注异常体系 五、异常的优缺点 在之前我们…...

【数据结构】哈希 ---万字详解

unordered系列关联式容器 在C98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到log_2 N,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好 的查询是&#xff0c…...

4399大数据面试题及参考答案(数据分析和数据开发)

对数据分析的理解 数据分析是一个从数据中提取有价值信息以支持决策的过程。它涵盖了数据收集、清洗、转换、建模和可视化等多个环节。 首先,数据收集是基础。这包括从各种数据源获取数据,例如数据库、文件系统、网络接口等。这些数据源可以是结构化的数据,如关系型数据库中…...

快速理解倒排索引在ElasticSearch中的作用

一.基础概念 定义: 倒排索引是一种数据结构,用来加速文本数据的搜索和检索,和传统的索引方式不同,倒排索引会被每个词汇项与包含该词汇项的文档关联起来,从而去实现快速的全文检索。 举例: 在传统的全文…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...