axios請求失敗自動重發


來源:https://wintc.top/article/53

在做Vue、React項目的時候常會用axios請求庫來與后端進行數據交互。我們通常采用一個用戶憑證token來驗證用戶身份,服務器根據token進行判斷當前用戶是否有權限調用接口。

經常遇到的一個問題是,調用接口時token可能已經過期,此時調用接口會失敗,需要重新登錄后再調用接口。通常我們可能處理為,用戶走完登錄流程后再重新手動觸發一次請求。這樣的實現本身沒什么問題,但是給用戶的操作體驗上有被中斷的感覺,今天嘗試解決了一下這個問題。

一、業務痛點

我的業務場景是,當一個接口(比如”用戶發表評論“)返回token過期或者未驗證的狀態碼時,調出登錄彈窗,登錄成功后再次發送評論請求。當然我們可以在評論接口處對狀態碼進行判斷,token失效則重新發送請求;如果有其它接口也類似處理。這個方法最大的問題在於對於每個接口都要單獨處理,然而程序員最大的優點就是——懶。這個方法雖然可行,對於一個懶人來說並不怎么好用,那更好的辦法的是什么呢?

 

二、業務實現——以登錄過期,重新發送請求為例(Vue實現)

axios請求攔截器本身可以獲取請求的地址、參數、超時時間等配置,請求的重發變得很簡單;同時axios庫的請求返回為一個promise對象,得益於Promise強大的嵌套異步處理,可以使得請求接口調用對請求重發“無感”——即調用接口的時候你可以默認它一定成功,因為失敗的情況在攔截器已經重發了。

1. 使用攔截器進行請求重發

function getToken () { return localStorage.getItem('token') } function clearToken () { localStorage.removeItem('token') } function setToken (token) { localStorage.setItem('token', token) } function login () { // 登錄處理代碼 } const instance = axios.create({ baseURL: 'http://xxxx', // 請求域名前綴 timeout: 10 * 1000 }) const requestError = error => Promise.reject(error) const beforeRequest = config => { config.headers['token'] = getToken() || undefined return config } const beforeResponse = res => () => { if (res.data.code == 401) { // 401錯誤表示未登錄授權或者token失效 clearToken() return login().then(() => { return instance.request(res.config) // 這里是核心代碼,登錄成功后重新請求!返回Promise對象。 }) } return res } instance.interceptors.request.use(beforeRequest, requestError) instance.interceptors.response.use(beforeResponse, requestError)

2.登錄調用(login函數)封裝

上述代碼里重新請求部分調用了login函數(login().then(callback)),login函數體空置了,接下來將討論其實現。login預期返回一個Proimise,登錄成功則Promise.then注冊的回調函數將被調用。

 我們可以將登錄彈窗封裝為一個組件,然后通過手動掛載組件來函數式地調用登錄流程。可以在登錄組件內部提供一個函數以供外部login函數調用,比如showModal,該函數直接返回一個Promise,login函數只要調用該函數並直接返回即可。

登錄組件Login.vue封裝:

<template> <div v-show="show"> <!-- 登錄框 --> </div> </template> <script> export default { data () { return { username: '', password: '', resolve: null, reject: null, show: false } }, methods: { showModal () { return new Promise((resolve, rejcet) => { this.show = true this.resolve = resolve this.reject = reject }) }, hideModal () { this.show = false this.reject = null this.resolve = null this.username = '' this.password = '' }, success () { this.hideModal() this.resolve && this.resolve() }, fail () { this.hideModal() this.reject && this.reject() } } } </script>

封裝好了Login.vue組件,接下來實現login函數:

import Login from '@/components/Login.vue' import Vue from 'vue' // ... let vm = null function login() { if (!vm) { const LoginConstructor = Vue.extend(Login) vm = new LoginConstructor().$mount() } return vm.showModal() } // ...

login函數閉包了一個外部變量vm,目的是通過vm引用已創建的Login組件實例,避免重復創建(即“單例”)。這樣,完整的登錄后重發請求流程即完成了。

 

 

三、總結

一般而言只要談到異步,通常提到回調函數。JS里的Promise是一個強大的回調函數管理器。本文的實現方案正是利用了Promise的特性,在接口無權限時,將“登錄+重新請求”的過程封裝為Promise並返回,實現接口調用過程中無權限登錄統一處理。這樣在接口調用的地方,可以不用單獨處理無權限的情況,一定程度上避免用戶操作被登錄流程打斷。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM