js無痛刷新Token的實(shí)現(xiàn)
這個(gè)需求場(chǎng)景很常見,幾乎很多項(xiàng)目都會(huì)用上,之前項(xiàng)目也實(shí)現(xiàn)過,最近剛好有個(gè)項(xiàng)目要實(shí)現(xiàn),重新梳理一番。
需求
對(duì)于需要前端實(shí)現(xiàn)無痛刷新Token,無非就兩種:
- 請(qǐng)求前判斷Token是否過期,過期則刷新
- 請(qǐng)求后根據(jù)返回狀態(tài)判斷是否過期,過期則刷新
處理邏輯
實(shí)現(xiàn)起來也沒多大差別,只是判斷的位置不一樣,核心原理都一樣:
- 判斷
Token
是否過期沒過期則正常處理
過期則發(fā)起刷新Token
的請(qǐng)求拿到新的
Token
保存重新發(fā)送
Token
過期這段時(shí)間內(nèi)發(fā)起的請(qǐng)求
重點(diǎn):
- 保持
Token
過期這段時(shí)間發(fā)起請(qǐng)求狀態(tài)(不能進(jìn)入失敗回調(diào)) - 把刷新
Token
后重新發(fā)送請(qǐng)求的響應(yīng)數(shù)據(jù)返回到對(duì)應(yīng)的調(diào)用者
實(shí)現(xiàn)
- 創(chuàng)建一個(gè)flag
isRefreshing
來判斷是否刷新中 - 創(chuàng)建一個(gè)數(shù)組隊(duì)列
retryRequests
來保存需要重新發(fā)起的請(qǐng)求 - 判斷到
Token
過期isRefreshing = false
的情況下 發(fā)起刷新Token
的請(qǐng)求刷新
Token
后遍歷執(zhí)行隊(duì)列retryRequests
isRefreshing = true
表示正在刷新Token
,返回一個(gè)Pending
狀態(tài)的Promise
,并把請(qǐng)求信息保存到隊(duì)列retryRequests
中
import axios from "axios"; import Store from "@/store"; import Router from "@/router"; import { Message } from "element-ui"; import UserUtil from "@/utils/user"; // 創(chuàng)建實(shí)例 const Instance = axios.create(); Instance.defaults.baseURL = "/api"; Instance.defaults.headers.post["Content-Type"] = "application/json"; Instance.defaults.headers.post["Accept"] = "application/json"; // 定義一個(gè)flag 判斷是否刷新Token中 let isRefreshing = false; // 保存需要重新發(fā)起請(qǐng)求的隊(duì)列 let retryRequests = []; // 請(qǐng)求攔截 Instance.interceptors.request.use(async function(config) { Store.commit("startLoading"); const userInfo = UserUtil.getLocalInfo(); if (userInfo) { //業(yè)務(wù)需要把Token信息放在 params 里面,一般來說都是放在 headers里面 config.params = Object.assign(config.params ? config.params : {}, { appkey: userInfo.AppKey, token: userInfo.Token }); } return config; }); // 響應(yīng)攔截 Instance.interceptors.response.use( async function(response) { Store.commit("finishLoading"); const res = response.data; if (res.errcode == 0) { return Promise.resolve(res); } else if ( res.errcode == 30001 || res.errcode == 40001 || res.errcode == 42001 || res.errcode == 40014 ) { // 需要刷新Token 的狀態(tài) 30001 40001 42001 40014 // 拿到本次請(qǐng)求的配置 let config = response.config; // 進(jìn)入登錄頁面的不做刷新Token 處理 if (Router.currentRoute.path !== "/login") { if (!isRefreshing) { // 改變flag狀態(tài),表示正在刷新Token中 isRefreshing = true; // 刷新Token return Store.dispatch("user/relogin") .then(res => { // 設(shè)置刷新后的Token config.params.token = res.Token; config.params.appkey = res.AppKey; // 遍歷執(zhí)行需要重新發(fā)起請(qǐng)求的隊(duì)列 retryRequests.forEach(cb => cb(res)); // 清空隊(duì)列 retryRequests = []; return Instance.request(config); }) .catch(() => { retryRequests = []; Message.error("自動(dòng)登錄失敗,請(qǐng)重新登錄"); const code = Store.state.user.info.CustomerCode || ""; // 刷新Token 失敗 清空緩存的用戶信息 并調(diào)整到登錄頁面 Store.dispatch("user/logout"); Router.replace({ path: "/login", query: { redirect: Router.currentRoute.fullPath, code: code } }); }) .finally(() => { // 請(qǐng)求完成后重置flag isRefreshing = false; }); } else { // 正在刷新token,返回一個(gè)未執(zhí)行resolve的promise // 把promise 的resolve 保存到隊(duì)列的回調(diào)里面,等待刷新Token后調(diào)用 // 原調(diào)用者會(huì)處于等待狀態(tài)直到 隊(duì)列重新發(fā)起請(qǐng)求,再把響應(yīng)返回,以達(dá)到用戶無感知的目的(無痛刷新) return new Promise(resolve => { // 將resolve放進(jìn)隊(duì)列,用一個(gè)函數(shù)形式來保存,等token刷新后直接執(zhí)行 retryRequests.push(info => { // 將新的Token重新賦值 config.params.token = info.Token; config.params.appkey = info.AppKey; resolve(Instance.request(config)); }); }); } } return new Promise(() => {}); } else { return Promise.reject(res); } }, function(error) { let err = {}; if (error.response) { err.errcode = error.response.status; err.errmsg = error.response.statusText; } else { err.errcode = -1; err.errmsg = error.message; } Store.commit("finishLoading"); return Promise.reject(err); } ); export default Instance;
到此這篇關(guān)于js無痛刷新Token的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)js無痛刷新Token內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
原生JavaScript實(shí)現(xiàn)批量獲取表單數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了如何使用原生JavaScript實(shí)現(xiàn)批量獲取表單數(shù)據(jù),文中的示例代碼講解詳細(xì),有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01微信小程序?qū)崿F(xiàn)錄制、試聽、上傳音頻功能(帶波形圖)
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)錄制、試聽、上傳音頻功能(帶波形圖),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02帶有定位當(dāng)前位置的百度地圖前端web api實(shí)例代碼
這篇文章主要介紹了帶有定位當(dāng)前位置的百度地圖前端web api實(shí)例代碼 的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06微信小程序?qū)崙?zhàn)之網(wǎng)易云音樂歌曲詳情頁實(shí)現(xiàn)代碼
本文給大家介紹了微信小程序?qū)W習(xí)記錄之網(wǎng)易云音樂歌曲詳情頁代碼實(shí)現(xiàn),代碼分為html、css和js部分,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05SpringMVC+bootstrap table實(shí)例詳解
本文通過實(shí)例給大家介紹了SpringMVC+bootstrap-table,需要的朋友可以參考下2017-06-06