封裝 axios 實現自動重試

爲何寫這個題目呢?
由於以前寫的一個 Node 程序有點小問題,使用的 axios 經過代理請求數據,代理服務器(阿布雲)時不時抽風(40七、41三、503)。前端

由於第一次寫的時候當作一個 DEMO 去實現的,寫的挺簡陋,只能說大致功能對,可是沒有容錯機制ios

這裏咱們先算一筆賬啊,一次請求等於 1+100 次,由於我內部還會請求好多數據。
若是隻是第一次失敗了,那麼可有可無,大不了重發一次。
可是若是是後面 100 次中有極個別暴雷了,那麼就會致使整個101次請求所有做廢。(由於返回的數據是錯誤的,使用者會觸發第二次請求。不止加劇了服務器的壓力,還增長了使用者檢查的壓力axios

好了,爲何實現這個功能說了,那麼咱們要開始實現了。服務器

axios 發起請求

axios 發請求仍是很簡單的,那麼咱們能夠直接仿照他來實現一下封裝。微信

axios({
    url: 'https://www.lilnong.top/cors/axiosAutoTry',
    params: 'user=sf',
    method: 'get'
})
.then(console.log)
.catch(console.log)

image.png

實現自動重試

我直接在 data 上增長一個 __try_count 用於設置重試次數。併發

由於 Axios 是支持 Promise,因此咱們的方法也支持。
axios 若是成功了咱們也 resolve。
axios 若是失敗了咱們先判斷次數,而後根據具體的錯誤,進行重試。cors

  • 407 就是我理解的抽風
  • 413 是請求併發過高,爲了避免佔用多少能夠加個延時器。
  • 503 也是我理解的抽風
  • ECONNABORTED 很奇怪好好的資源他也不加載就卡住了,因此我設置了 timeout
  • ECONNRESET 也是一個很奇怪的錯誤。(既然是 Node,我理解他常常出錯誤。)
function axiosAutoTry(data){
    return new Promise((resolve, reject)=>{
        axios(data)
        .then((data)=>{
            resolve(data)
        })
        .catch(error=>{
            // 有重試次數
            if(typeof data.__try_count == 'number' && data.__try_count>0){
                console.error('重試請求', error.message, data)
                data.__try_count--;
                if(error.code == 'ECONNABORTED'){
                    // 停止,超時
                    return resolve(axiosAutoTry(data))
                }else if(error.code == 'ECONNRESET'){
                    // 
                    return resolve(axiosAutoTry(data))
                }else{
                    if(error.response && error.response.status == 407){
                        // 代理407
                        return setTimeout(v=>{
                            resolve(axiosAutoTry(data))
                        }, 500 + Math.random() * 500)
                    }else if(error.response && error.response.status == 503){
                        // 服務器異常
                        return setTimeout(v=>{
                            resolve(axiosAutoTry(data))
                        }, 1000 + Math.random() * 500)
                    }else if(error.response && error.response.status == 429){
                        // 併發超過限制
                        return setTimeout(v=>{
                            resolve(axiosAutoTry(data))
                        }, 1000 + Math.random() * 1000)
                    }
                    // console.error('異常錯誤', error)
                }
            }
            reject(error)
        })
    })
}

微信公衆號:前端linong

歡迎你們關注個人公衆號。有疑問也能夠加個人微信前端交流羣。
clipboard.pngdom

相關文章
相關標籤/搜索