axios二次封裝學習

封裝的必要性

咱們在使用axios進行異步操做時,可能會遇到如下狀況:css

  • 對一個按鈕頻繁點擊,發送屢次請求
  • axios的規範寫法中:
    axios.post(url, data).then(res=>{}).catch(err=>{})
    複製代碼
    這裏咱們發現咱們每一次寫的時候,都須要寫.catch(err=>{}),會形成代碼的冗餘

封裝過程

攔截器科普

// 添加請求攔截器
axios.interceptors.request.use(function (config) {
    // 在發送請求以前作些什麼
    return config;
}, function (error) {
    // 對請求錯誤作些什麼
    return Promise.reject(error);
});
// 添加響應攔截器
axios.interceptors.response.use(function (response) {
    // 對響應數據作點什麼
    return response;
}, function (error) {
    // 對響應錯誤作點什麼
    return Promise.reject(error);
});
複製代碼

取消請求處理方法科普

var CancelToken = axios.CancelToken;
var cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // executor 函數接收一個 cancel 函數做爲參數
    cancel = c;
  })
});

// 取消請求
cancel();
複製代碼

本文代碼

axios.js
設置一個cancelFlag做爲標誌符,默認爲true,在請求攔截器時,判斷若是cancelFlag爲true,就能夠發送請求,且將cancelFlag設爲false。當cancelFlag爲false,就取消請求。在響應攔截器中再將cancelFlag設爲true。說明只用當一個請求發送且收到響應後,才能夠發送另外一個請求。這裏存在的問題:cancelFlag是全局變量,這樣多頁面多個接口請求時,互相會有影響這裏的解決辦法就是在axios.js中構建構造函數,這樣可讓cancelFlag私有化,可是這樣的方式會致使佔有大量內存。
參考同事寫的代碼(版本二),我以爲很是的有道理。並且比較簡單。
版本1、使用cancelFlag全局變量判斷vue

import Vue from 'vue'
import axios from 'axios'
import {Indicator} from 'mint-ui'
Vue.component(Indicator)
let CancelToken = axios.CancelToken //取消請求
let cancelFlag = true
//設置公共部分,請求頭和超時時間
axios.defaults.headers = {
    'X-Requested-With': 'XMLHttpRequest'
}
axios.defaults.timeout = 20000
//在請求攔截器時
axios.interceptors.request.use(config => {
    if (cancelFlag) {
        cancelFlag = false
        Indicator.open()
    } else {
        cancelToken: new CancelToken (c => {
            cancel = c
        })
        cancel()
    }
    return config
}, error => {
    return Promise.reject(error)
})
axios.interceptors.response.use(config => {
    cancelFlag = true
    Indicator.close()
    return config
}, error => {
    //
})
複製代碼

版本2、異步請求時,帶上一個參數requestName。
這裏一開始的疑惑是,當請求a帶上參數requestName後,發送屢次請求,判斷axios[requestName]和axios[requestName].cancel存在時,會作取消處理。那發送成功後,再點擊時,axios[requestName]和axios[requestName].cancel仍是會存在啊。這樣仍是會執行axios[requestName].cancel()。
這裏是由於當上一次請求發送成功後,其axios[requestName].cancel這個方法已經失效,即便執行了這個方法也不起做用。axios[requestName].cancel的值永遠是上一次的請求的取消回調。當上一次請求成功後,該回調會失效。ios

axios.interceptors.request.use(config => {
    let requestName = config.data.requestName
    if (requestName) {
        if (axios[requestName] && axios[requestName].cancel) {
            axios[requestName].cancel()
        }
        config.cancelToken = new CancelToken (c => {
            axios[requestName] = {}
            axios[requestName].cancel = c
        })
    }
    return config
}, error => {
    return Promise.reject(error)
})
複製代碼

響應的錯誤處理封裝git

axios.interceptors.response.use(config => {
    Indicator.close()
    return config
}, error => {
    cancelFlag = true
    Indicator.close()
    if (error && error.response) {
        switch (error.response.status) {
            case 400:
                error.message = '錯誤請求'
                break;
            case 401:
                error.message = '未受權,請從新登陸'
                break;
            case 403:
                error.message = '拒絕訪問'
                break;
            case 404:
                error.message = '請求錯誤,未找到該資源'
                break;
            case 405:
                error.message = '請求方法未容許'
                break;
            case 408:
                error.message = '請求超時'
                break;
            case 500:
                error.message = '服務器端出錯'
                break;
            case 501:
                error.message = '網絡未實現'
                break;
            case 502:
                error.message = '網絡錯誤'
                break;
            case 503:
                error.message = '服務不可用'
                break;
            case 504:
                error.message = '網絡超時'
                break;
            case 505:
                error.message = 'http版本不支持該請求'
                break;
            default:
            error.message = `鏈接錯誤${error.response.status}`
        }
      } else {
        error.message = "鏈接到服務器失敗"
      }
    return Promise.reject(error.message)
})
複製代碼

http.js(封裝了post和get請求)
在axios.js文件裏對響應攔截器作了判斷error.response.status的值的處理,根據不一樣的狀態碼返回不一樣的error說明。在http.js文件裏post和get函數的參數爲三個,第三個參數error就是出現錯誤時的文案。使用該api能夠本身設置該文案,若是不傳這個參數,那麼就返回axios.js設置的error文案github

import Vue from 'vue'
import axios from './axios'
import 'mint-ui/lib/style.css';
import {Toast} from 'mint-ui'
Vue.component(Toast)
export function post (url, data, error) {
    return new Promise((resolve, reject) => {
        axios.post(url, data).then(res => {
            resolve(res)
        }, err => {
            err = error ? error : err
            Toast({
                message: err,
                duration: 500
            })
        })
    })
}
export function get (url, data, error) {
    return new Promise((resolve, reject) => {
        axios.post(url, {
            data: data
        }).then(res => {
            resolve(res)
        }, err => {
            err = error ? error : err
            Toast({
                message: err,
                duration: 500
            })
        })
    })
}
複製代碼

使用

1)在main.js引入文件axios

import axios from '../utils/axios.js'
import {post, get} from '../utils/http.js'
Vue.prototype.$axios = axios
Vue.prototype.$post = post
Vue.prototype.$get = get
複製代碼

2)組件中使用api

this.$post('/api/saveInfo', {
    value: this.value,
    requestName: 'name01'
}, '請求失敗啦~~~').then(res => {
    // alert(res.data)
})
複製代碼

代碼:github地址連接服務器

相關文章
相關標籤/搜索