欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue中如何處理token過期問題

 更新時間:2022年10月13日 12:04:38   作者:燕穗子博客  
這篇文章主要介紹了Vue中如何處理token過期問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

后端為了安全,token一般存在有效時間,當(dāng)token過期,所有請求失效

解決方案

方案一

在請求發(fā)起前攔截每個請求,判斷token的有效時間是否已經(jīng)過期,若已過期,則將請求掛起,先刷新token后再繼續(xù)請求。

  • 優(yōu)點: 在請求前攔截,能節(jié)省請求,省流量
  • 缺點: 需要后端額外提供一個token過期時間的字段;使用了本地時間判斷,若本地時間被篡改,特別是本地時間比服務(wù)器時間慢時,攔截會失敗
  • 使用方法:axios.interceptors.request.use() 這個請求前攔截方法

方案二

根據(jù)攔截返回后的數(shù)據(jù)判斷,若token過期,先刷新token,再進行一次請求。

  • 優(yōu)點:不需額外的token過期字段,不需判斷時間
  • 缺點: 會消耗多一次請求,耗流量
  • 使用方法:axios.interceptors.response.use() 這個響應(yīng)攔截方法

最簡單方法:獲取到過期code,直接跳到登錄頁 

方案三:封裝axios基本結(jié)構(gòu)

1、token是存在localStorage中

//在request.js
?
import axios from 'axios'
?
// 創(chuàng)建一個實例
const service = axios.create({
? ? baseURL: process.env.VUE_APP_BASE_API,?
? ? timeout: 5000 // request timeout
})
?
// 從localStorage中獲取token
function getLocalToken () {
? ? const token = window.localStorage.getItem('token')
? ? return token
}
?
// 給實例添加一個setToken方法,用于登錄后將最新token動態(tài)添加到header,同時將token保存在localStorage中
service.setToken = (token) => {
? instance.defaults.headers['X-Token'] = token
? window.localStorage.setItem('token', token)
}
?
// 攔截返回的數(shù)據(jù)
service.interceptors.response.use(response => {
? // 接下來會在這里進行token過期的邏輯處理
? return response
}, error => {
? return Promise.reject(error)
})
?
//暴露
export default service

假如后端接口token過期返回的code是401

//獲取新的token請求
function refreshToken () {
? ? return service.post('/refreshtoken').then(res => res.data)
}
?
// 攔截返回的數(shù)據(jù)
service.interceptors.response.use(response => {
? // 接下來會在這里進行token過期的邏輯處理
? const { code } = response.data
? ?? ?-----------------------------------------------------------
? ?? ?// 說明token過期了,獲取新的token
?? ? if (code === 401) {
?? ??? ?return refreshToken().then(res => {
?? ??? ?// 刷新token成功,將最新的token更新到header中,同時保存在localStorage中
?? ? ? ? ?const { token } = res.data
?? ? ? ? ?service.setToken(token)
?? ? ? ? ?
?? ? ? ? ?// 獲取當(dāng)前失敗的請求
?? ? ? ? ?const config = response.config
?? ? ? ? ?//重置失敗請求的配置
?? ? ? ? ?config.headers['X-Token'] = token
?? ? ? ? ?config.baseURL = '' "
?? ? ? ? ?//重試當(dāng)前請求并返回promise
?? ? ? ? ?return service(config)
?? ??? ?}).catch( res=>{
?? ??? ??? ?//重新請求token失敗,跳轉(zhuǎn)到登錄頁
?? ??? ??? ?window.location.href = '/login '
?? ??? ?} )
?? ? }
?? ? --------------------------------------------------------------
? return response
?
}, error => {
? return Promise.reject(error)
})

2、問題和優(yōu)化

如果token失效時,存在多個請求,這就會導(dǎo)致多次執(zhí)行刷新token的接口

在request.js中用一個變量來標(biāo)記當(dāng)前是否正在刷新token的狀態(tài),如果正在刷新則不再調(diào)用刷新token的接口 

在request.js 

// 是否正在刷新的標(biāo)記
let isRefreshing = false
?
-----------------------------------------------------------
? ?? ?// 說明token過期了,獲取新的token
?? ? if (code === 401) {
?? ? ?? ?//判斷一下狀態(tài)
?? ??? ?if( !isRefreshing ){
?? ??? ??? ?//修改狀態(tài),進入更新token階段
?? ??? ??? ?isRefreshing = true
?? ??? ??? ?
?? ??? ??? ?return refreshToken().then(res => {
?? ??? ??? ?// 刷新token成功,將最新的token更新到header中,同時保存在localStorage中
?? ??? ? ? ? ?const { token } = res.data
?? ??? ? ? ? ?service.setToken(token)
?? ??? ? ? ? ?
?? ??? ? ? ? ?// 獲取當(dāng)前失敗的請求
?? ??? ? ? ? ?const config = response.config
?? ??? ? ? ? ?//重置失敗請求的配置
?? ??? ? ? ? ?config.headers['X-Token'] = token
?? ??? ? ? ? ?config.baseURL = '' "
?? ??? ? ? ? ?//重試當(dāng)前請求并返回promise
?? ??? ? ? ? ?return service(config)
?? ??? ??? ?}).catch( res=>{
?? ??? ??? ??? ?//重新請求token失敗,跳轉(zhuǎn)到登錄頁
?? ??? ??? ??? ?window.location.href = '/login '
?? ??? ??? ?} ).finally( ()=>{
?? ??? ??? ??? ?//完成之后在關(guān)閉狀態(tài)
?? ??? ??? ??? ?isRefreshing = false
?? ??? ??? ?} )
?? ??? ?}
?? ? }

同時發(fā)起兩個或以上的請求時,其他接口如何重試

兩個接口幾乎同時發(fā)起和返回,第一個接口會進入刷新token后重試的流程,而第二個接口需要先存起來,然后等刷新token后再重試。同樣,如果同時發(fā)起三個請求,此時需要緩存后兩個接口,等刷新token后再重試;

當(dāng)?shù)诙€過期的請求進來,token正在刷新,我們先將這個請求存到一個數(shù)組隊列中,想辦法讓這個請求處于等待中,一直等到刷新token后再逐個重試清空請求隊列。

將請求存進隊列中后,同時返回一個Promise,讓這個Promise一直處于Pending狀態(tài)(即不調(diào)用resolve),此時這個請求就會一直等啊等,只要我們不執(zhí)行resolve,這個請求就會一直在等待。當(dāng)刷新請求的接口返回來后,我們再調(diào)用resolve,逐個重試。

// 是否正在刷新的標(biāo)記
let isRefreshing = false
// 重試隊列,每一項將是一個待執(zhí)行的函數(shù)形式
let requests = []
?
-----------------------------------------------------------
? ?? ?// 說明token過期了,獲取新的token
?? ? if (code === 401) {
?? ? ?? ?const config = response.config
?? ? ?? ?//判斷一下狀態(tài)
?? ??? ?if( !isRefreshing ){
?? ??? ??? ?//修改狀態(tài),進入更新token階段
?? ??? ??? ?isRefreshing = true
?? ??? ??? ?// 獲取當(dāng)前的請求
?? ??? ??? ?return refreshToken().then(res => {
?? ??? ??? ?// 刷新token成功,將最新的token更新到header中,同時保存在localStorage中
?? ??? ? ? ? ?const { token } = res.data
?? ??? ? ? ? ?service.setToken(token)
?? ??? ? ? ? ?
?? ??? ? ? ? ?//重置失敗請求的配置
?? ??? ? ? ? ?config.headers['X-Token'] = token
?? ??? ? ? ? ?config.baseURL = '' "
?? ??? ? ? ? ?
?? ??? ? ? ? ?//已經(jīng)刷新了token,將所有隊列中的請求進行重試
?? ??? ? ? ? ?requests.forEach(cb => cb(token))
?? ??? ? ? ? ?// 重試完了別忘了清空這個隊列
?? ??? ? ? ? ?requests = []
?? ??? ? ? ? ?
?? ??? ? ? ? ?return service(config)
?? ??? ??? ?}).catch( res=>{
?? ??? ??? ??? ?//重新請求token失敗,跳轉(zhuǎn)到登錄頁
?? ??? ??? ??? ?window.location.href = '/login '
?? ??? ??? ?} ).finally( ()=>{
?? ??? ??? ??? ?//完成之后在關(guān)閉狀態(tài)
?? ??? ??? ??? ?isRefreshing = false
?? ??? ??? ?} )
?? ??? ?} else{
?? ??? ??? ? // 正在刷新token,返回一個未執(zhí)行resolve的promise
?? ??? ??? ? return new Promise((resolve) => {
?? ? ? ? ? ? // 將resolve放進隊列,用一個函數(shù)形式來保存,等token刷新后直接執(zhí)行
?? ??? ? ? ? ? ? requests.push((token) => {
?? ??? ??? ? ? ? ? ? ?config.baseURL = ''
?? ??? ??? ? ? ? ? ? ?config.headers['X-Token'] = token
?? ??? ??? ? ? ? ? ? ?resolve(instance(config))
?? ??? ? ? ? ? ?? ? })
?? ? ? ? ?? ? })
?? ??? ?}
?? ? }

3、完整版

//在request.js
?
import axios from 'axios'
?
// 是否正在刷新的標(biāo)記
let isRefreshing = false
// 重試隊列,每一項將是一個待執(zhí)行的函數(shù)形式
let requests = []
?
// 創(chuàng)建一個實例
const service = axios.create({
? ? baseURL: process.env.VUE_APP_BASE_API,?
? ? timeout: 5000 // request timeout
})
?
// 從localStorage中獲取token
function getLocalToken () {
? ? const token = window.localStorage.getItem('token')
? ? return token
}
?
// 給實例添加一個setToken方法,用于登錄后將最新token動態(tài)添加到header,同時將token保存在localStorage中
service.setToken = (token) => {
? instance.defaults.headers['X-Token'] = token
? window.localStorage.setItem('token', token)
}
?
//獲取新的token請求
function refreshToken () {
? ? return service.post('/refreshtoken').then(res => res.data)
}
?
// 攔截返回的數(shù)據(jù)
service.interceptors.response.use(response => {
? // 接下來會在這里進行token過期的邏輯處理
? const { code } = response.data
?? ?-----------------------------------------------------------
? ?? ?// 說明token過期了,獲取新的token
?? ? if (code === 401) {
?? ? ?? ?const config = response.config
?? ? ?? ?//判斷一下狀態(tài)
?? ??? ?if( !isRefreshing ){
?? ??? ??? ?//修改狀態(tài),進入更新token階段
?? ??? ??? ?isRefreshing = true
?? ??? ??? ?// 獲取當(dāng)前的請求
?? ??? ??? ?return refreshToken().then(res => {
?? ??? ??? ?// 刷新token成功,將最新的token更新到header中,同時保存在localStorage中
?? ??? ? ? ? ?const { token } = res.data
?? ??? ? ? ? ?service.setToken(token)
?? ??? ? ? ? ?
?? ??? ? ? ? ?//重置失敗請求的配置
?? ??? ? ? ? ?config.headers['X-Token'] = token
?? ??? ? ? ? ?config.baseURL = '' "
?? ??? ? ? ? ?
?? ??? ? ? ? ?//已經(jīng)刷新了token,將所有隊列中的請求進行重試
?? ??? ? ? ? ?requests.forEach(cb => cb(token))
?? ??? ? ? ? ?// 重試完了別忘了清空這個隊列
?? ??? ? ? ? ?requests = []
?? ??? ? ? ? ?
?? ??? ? ? ? ?return service(config)
?? ??? ??? ?}).catch( res=>{
?? ??? ??? ??? ?//重新請求token失敗,跳轉(zhuǎn)到登錄頁
?? ??? ??? ??? ?window.location.href = '/login '
?? ??? ??? ?} ).finally( ()=>{
?? ??? ??? ??? ?//完成之后在關(guān)閉狀態(tài)
?? ??? ??? ??? ?isRefreshing = false
?? ??? ??? ?} )
?? ??? ?} else{
?? ??? ??? ? // 正在刷新token,返回一個未執(zhí)行resolve的promise
?? ??? ??? ? return new Promise((resolve) => {
?? ? ? ? ? ? // 將resolve放進隊列,用一個函數(shù)形式來保存,等token刷新后直接執(zhí)行
?? ??? ? ? ? ? ? requests.push((token) => {
?? ??? ??? ? ? ? ? ? ?config.baseURL = ''
?? ??? ??? ? ? ? ? ? ?config.headers['X-Token'] = token
?? ??? ??? ? ? ? ? ? ?resolve(instance(config))
?? ??? ? ? ? ? ?? ? })
?? ? ? ? ?? ? })
?? ??? ?}
?? ? }
?? ? --------------------------------------------------------------
? return response
}, error => {
? return Promise.reject(error)
})
//暴露
export default service

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論