前端Token管理(获取、过期处理、异常处理及优化)

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

* 登录页面使用(伪代码)

import Vue from ‘vue’

import { login } from ‘@/services/user’

export default Vue.extend({

name: ‘LoginIndex’,

data() {

return {

formData: {

phone: ‘18201288771’,

password: ‘111111’

}

}

},

methods: {

async submit() {

try {

const { data } = await login(this.formData)

// 处理请求结果

if (data.state !== 1) {

this.KaTeX parse error: Expected 'EOF', got '}' at position 37: …ssage) }̲ else { …store.commit(‘setUser’, data.content)

this.$message.success(‘登录成功’)

}

} catch (error) {}

this.isLoading = false

}

}

})

* axios请求拦截器

// 请求拦截器,每一个请求都会经过此拦截器。

request.interceptors.request.use((config) => {

// 在请求的header中设置token

config.headers.Authorization = store.state?.user?.access_token

return config

}, (error) => {

return Promise.reject(error)

})

![](https://img-blog.csdnimg.cn/img_convert/de6d3f4387011d6d6be5b32007941a96.png)
#### 优化——授权过期登录重新返回页面
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210525173940921.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyOTMwODYz,size_16,color_FFFFFF,t_70#pic_center)
##### request.js中

// 跳转至首页封装

const redirectLogin = () => {

router.push({

name: ‘login’,

query: {

// 通过参数传 登录成功后的跳转地址

redirect: router.currentRoute.fullPath

}

})

}

##### 登录页面

methods: {

// 登录请求方法

async submit() {

try {

const { data } = await login(this.formData)

// 处理请求结果

if (data.state !== 1) {

//… 登录失败处理逻辑

} else {

//… 登录成功处理逻辑

// 登录成功后进行路由跳转

this. r o u t e r . p u s h ( ( t h i s . router.push((this. router.push((this.route.query.redirect as string) || ‘/’)

}

} catch (error) {}

}

}

#### 优化——页面刷新Token丢失

export default new Vuex.Store({

state: {

// 初始化时从本地存储中获取

user: JSON.parse(window.localStorage.getItem(‘user’) || ‘null’)

},

mutations: {

//设置用户登录信息

setUser(state, payload) {

//因目前后端返回的是json字符串,所以我转义了一下

payload = JSON.parse(payload)

//如果pyload中没有过期时间并且存在过期时间长度

if (!payload.expires_at && payload.expires_in) {

//设置过期时间

payload.expires_at = new Date().getTime() + payload.expires_in * 1000

}

//赋值

state.user = payload

//每次设置用户登录信息都存储值本地存储

window.localStorage.setItem(‘user’, JSON.stringify(payload))

}

},

actions: {

},

modules: {

}

})

### 过期维护
过期维护存前端存在两种方式
* 在请求发起前拦截每个请求,判断token的有效时间是否已经过期。若已过期,则将请求挂起,先刷新token后在继续请求。
	+ 优点:请求前拦截,节省请求及流量
	+ 缺点:需要后端额外提供过期时间字段,若本地时间与服务器时间不一致可能存在拦截失败。
* 不在请求前拦截,而是拦截返回后的数据。先放弃请求,接口返回过期后,先刷新token,在进行一次重试。
	+ 优点:不需要额外的token过期字段及判断时间
	+ 缺点:会消耗多一次请求,耗流量
#### 请求发起前拦截
![](https://img-blog.csdnimg.cn/img_convert/360aadadceef2e95d03a3986feb10898.png)

// 跳转首页逻辑

const redirectLogin = () => {

router.push({

name: ‘login’,

query: {

redirect: router.currentRoute.fullPath

}

})

}

// 刷新token后的任务队列

let refreshTokenArray = []

/**

* 刷新token,重新请求

*/

const refreshTokenFn = async () => {

// 判断是否有刷新token

const refreshToken = store.state?.user?.refresh_token || ‘’

// 如果刷新token存在

if (refreshToken) {

// 使用重新创建的axios请求,防止递归调用

const { data } = await axios.create()({

method: ‘POST’,

url: ‘/front/user/refresh_token’,

data: qs.stringify({

refreshtoken: refreshToken

})

})

//如果获取token失败 抛出异常

if (!data.content) throw new Error(‘refreshToken is faild’)

// 重新设置token

store.commit(‘setUser’, data.content)

return true

}

throw new Error(‘refreshToken not find’)

}

// 请求拦截器

request.interceptors.request.use(async (config: Config) => {

// 获取用户登录信息

const user = store.state?.user

// 判断access_token 是否过期且接口是否需要token

if (config.isAuthToken && user.expires_at < new Date().getTime()) {

// 是否正在执行刷新token

if (!refreshTokenLoding) {

try {

//刷新token锁为true

refreshTokenLoding = true

await refreshTokenFn()

// 执行获取token后的任务队列

refreshTokenArray.forEach(item => item())

//清空任务队列

refreshTokenArray = []

return config

} catch (error) {

// 如果刷新失败跳转登录页面

redirectLogin()

} finally {

// 无论成功失败消除

refreshTokenLoding = false

}

} else {

// 如果这正在刷新,返回一个 Promise ,并向刷新token成功后执行队列push 函数.

return new Promise(resolve => {

refreshTokenArray.push(() => {

// 返回config请求对象

resolve(config)

})

})

}

}

return config

})

#### 请求发起后拦截
![img](https://img-blog.csdnimg.cn/img_convert/6e0afa2515a202daee9e323075ad0604.png)
![img](https://img-blog.csdnimg.cn/img_convert/f9a0c0fa21a9d9dee0e14aad756d1b63.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**
图片转存中...(img-5NdvB8Ze-1715711482905)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**