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

山东大学软件学院项目实训-基于大模型的模拟面试系统-Token过期重定向问题

项目结构

├── assets/          # 静态资源(CSS/图片)
├── components/      # Vue 组件
├── layouts/         # 布局模板
├── pages/           # 自动生成路由
├── plugins/         # 插件(如 axios 拦截器)
├── store/           # Vuex 状态管理
├── nuxt.config.js   # 项目配置
└── middleware/      # 路由中间件

Token过期或者退出登录重定向问题

功能实现

添加一个响应拦截器每次请求前需要先验证用户Token有没有过期,如果过期了,那么就直接重定向到登陆页面让用户重新进行登录操作。

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxNDkxNDAyMjM0Iiwic3ViIjoiMTQ5MTQwMjIzNCIsImlhdCI6MTc0NTE0ODg3OX0.hWqI3bww_oQCcQlqyqsI56TJrfIE0qK6uTT5gxqbCko

根据local storage里的信息发现该token中载荷由以下三部分组成:

  • jti (JWT ID):令牌唯一标识符
  • sub (Subject):主题/用户ID
  • iat (Issued At):签发时间(Unix时间戳)

上面三部分并没有关于过期时间exp 的字段说明,但从local storage·还发现了auth._token_expiration.local字段,于是将该字段最为判断token是否过期的凭证。

// auth.js
export default {// 获取tokengetToken() {return localStorage.getItem('auth._token.local') || '';},// 检查token是否过期isTokenExpired() {const storedExpiration = localStorage.getItem('auth._token_expiration.local');if (storedExpiration) {const isExpired = Date.now() >= parseInt(storedExpiration, 10);if (isExpired) {console.warn('[Auth] Token expired (based on localStorage expiration)');return true;}}let token = this.getToken()console.log(token)if (token == "false") return true;},// 清除tokenclearToken() {localStorage.removeItem('auth._token.local');localStorage.removeItem('refreshToken');},// 保存token (用于登录成功后)saveToken(token, refreshToken) {localStorage.setItem('auth._token.local', token);if (refreshToken) {localStorage.setItem('refreshToken', refreshToken);}}};

之后利用auth.js里的函数完成拦截器:

import axios from 'axios';
import auth from './auth'; // 创建axios实例
const instance = axios.create({baseURL: process.env.VUE_APP_API_BASE_URL, // 从环境变量获取基础URLtimeout: 10000 // 请求超时时间
});instance.interceptors.request.use(config => {// 检查token是否过期if (auth.isTokenExpired()) {auth.clearToken();if (process.client) {// 使用 Nuxt 的 redirect 方法window.location.href = '/login'; }// 终止请求return Promise.reject(new Error('Token expired'));}const token = auth.getToken();if (token) {config.headers.Authorization = `Bearer ${token}`;}return config;},error => {// 请求错误处理return Promise.reject(error);}
);export default instance;

上述函数通过以下几步组成:

  1. Token检查:在每次请求前,通过auth.isTokenExpired()检查Token是否过期
  2. 过期处理:如果Token过期,则清除Token并重定向到登录页面
  3. Token添加:如果Token有效,则将其添加到请求头的Authorization字段中
  4. 错误处理:处理请求配置阶段的错误

Bug修改

完成上述实现之后,发现出现了下面这样的问题—列表类型的组件出现了非常多的重复的空的元素!!!但实际上正确的应该是只有一个面试官。
在这里插入图片描述
在这里插入图片描述

下面开始排查问题所在:

请求头携带的token格式错误

可能是多个并发请求同时检测到 Token 过期,导致多次重定向尝试。于是在下面添加一个类似于锁的机制:

// src/utils/axiosInstance.jslet isRedirecting = false; // 新添加
instance.interceptors.request.use(config => {if (auth.isTokenExpired() && !isRedirecting) { // 新添加isRedirecting = true;  // 新添加auth.clearToken();if (process.client) {window.location.href = '/login';}return Promise.reject(new Error('Token expired'));}return config;},error => {return Promise.reject(error);}
);

现在列表项的数目降到了3个。
在这里插入图片描述
但之后发现其实并不是isRedirecting 起了作用,而是将config.headers.Authorization = Bearer ${token};删了才起的作用。

这里是我完全解决了之后才回来重新写的
其实到了这一步后端就已经能返回正确的响应了,但当时并没有像之后那样看Network去分析,之前的问题就是我在拦截器里重新添加了Authorization,而偏偏我添加的是错的,这导致了之前会出现很多的空的项。
我通过分析Network里的没经过拦截器的请求头里的Authorization发现:Authorization里是没有Bearer的(见下图),之前加了Bearer反而错了

在这里插入图片描述

响应解封装错误

在这里插入图片描述
之后调试了很久,在Network里发现,后端明明相应了正确的请求,为什么会取不出来呢?
在这里插入图片描述
打印出来看一看,发现也没什么问题。

这是第二个问题,就是我使用了请求拦截器之后后端返回的响应不知道为什么会多封装一层,原本能够res.data取出的数据需要res.data.data才行,所以我就直接又加了一个响应拦截器。 (见下面代码)

instance.interceptors.response.use(response => {return response.data;},error => {// 处理HTTP错误状态码if (error.response) {switch (error.response.status) {case 401:window.location.href = '/login';break;}}// 返回错误信息return Promise.reject(error);}
);
http://www.xdnf.cn/news/651.html

相关文章:

  • 代码随想录算法训练营第三十五天|416. 分割等和子集、698.划分为k个相等的子集、473.火柴拼正方形
  • IDEA连接达梦数据库
  • Android学习之实战登录注册能力
  • Django 使用教程
  • 4月19日记(补)算了和周日一块写了 4月20日日记
  • 无法右键下载文档?网页PDF下载方法大全
  • Python赋能去中心化电子商务平台:重构交易生态的新未来
  • 2000-2017年各省天然气消费量数据
  • uni-app中map的使用
  • 52单片机LED实验
  • leetcode205.同构字符串
  • ​opencv图像库编程
  • 股票分析技术指标【MACD】
  • 基于Redis实现RAG架构的技术解析与实践指南
  • [Windows] Adobe Camera Raw 17.2 win/Mac版本
  • Java Streams 使用教程
  • 【Qt】QMainWindow类
  • go环境安装mac
  • QML中的JSON 处理
  • 字节跳动发布视频生成基础大模型 Seaweed-7B
  • 力扣刷题Day 21:两数之和(1)
  • 精打细算 - GPU 监控
  • 解决SQLserver中使用命令bcp,因权限问题无法将文件写入C盘
  • 今天分享一个网店客服回复数据集-用于网点客服AI助手自动回复智能体训练
  • 华硕原厂系统枪神9/9p超竟版-WIN11原装开箱出厂系统安装
  • 山东科技大学人工智能原理考试回忆复习资料
  • 基于autoware.1.14与gazebo联合仿真进行Hybrid A* 算法规划控制代价地图版
  • WhatTheDuck:一个基于浏览器的CSV查询工具
  • C语言指针2
  • 深度学习--mnist数据集实现卷积神经网络的手写数字识别