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