1. 程式人生 > >axios基於常見業務場景的二次封裝

axios基於常見業務場景的二次封裝

axios

axios 是一個基於 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中。在前端框架中的應用也是特別廣泛,不管是vue還是react,都有很多專案用axios作為網路請求庫。我在最近的幾個專案中都有使用axios,並基於axios根據常見的業務場景封裝了一個通用的request服務。

預設配置

定義全域性的預設配置

axios.defaults.timeout = 10000 //超時取消請求
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
axios.defaults.baseURL = process.env.BASE_URL //掛載在process下的環境常量,在我另一篇文章有詳細說明

自定義配置(非常見業務場景,僅作介紹)

// 建立例項時設定配置的預設值
var instance = axios.create({
  baseURL: 'https://api.another.com'
});
// 在例項已建立後修改預設值
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;

優先順序:自定義配置 > 預設配置

請求及響應攔截器

請求攔截器

// 請求列表
const requestList = []
axios.interceptors.request.use((config) => {
  //1.將當前請求的URL新增進請求列表陣列
  requestList.push(config.url)
  //2.請求開始,改變loading狀態供載入動畫使用
  store.dispatch('changeGlobalState', {loading: true})
  //3.從store中獲取token並新增到請求頭供後端作許可權校驗
  const token = store.getters.userInfo.token
  if (token) {
    config.headers.token = token
  }
  return config
}, function (error) {
  return Promise.reject(error)
})

1.請求攔截器中將所有請求的url新增進請求列表變數,為取消請求及loading狀態管理做準備2.請求一旦開始,就可以開啟動畫載入效果。3.使用者登入後可以在請求頭中攜帶token做許可權校驗使用。

響應攔截器

axios.interceptors.response.use(function (response) {
  // 1.將當前請求中請求列表中刪除
  requestList.splice(requestList.findIndex(item => item === response.config.url), 1)
  // 2.當請求列表為空時,更改loading狀態
  if (requestList.length === 0) {
    store.dispatch('changeGlobalState', {loading: false})
  }
  // 3.統一處理許可權認證錯誤管理
  if (response.data.code === 900401) {
    window.ELEMENT.Message.error('認證失效,請重新登入!', 1000)
    router.push('/login')
  }
  return response
}, function (error) {
  // 4.處理取消請求
  if (axios.isCancel(error)) {
    requestList.length = 0
    store.dispatch('changeGlobalState', {loading: false})
    throw new axios.Cancel('cancel request')
  } else {
    // 5.處理網路請求失敗
    window.ELEMENT.Message.error('網路請求失敗', 1000)
  }
  return Promise.reject(error)
})

1.響應返回後將相應的請求從請求列表中刪除2.當請求列表為空時,即所有請求結束,載入動畫結束3.許可權認證報錯統一攔截處理4.取消請求的處理需要結合其他程式碼說明5.由於專案後端並沒有採用RESTful風格的介面請求,200以外都歸為網路請求失敗

promise封裝及取消請求

const CancelToken = axios.CancelToken
//cancel token列表
let sources = []
const request = function (url, params, config, method) {
  return new Promise((resolve, reject) => {
    axios[method](url, params, Object.assign({}, config, {
    //1.通過將執行程式函式傳遞給CancelToken建構函式來建立cancel token
      cancelToken: new CancelToken(function executor (c) {
      //2.將cancel token存入列表
        sources.push(c)
      })
    })).then(response => {
      resolve(response.data)
    }, err => {
      if (err.Cancel) {
        console.log(err)
      } else {
        reject(err)
      }
    }).catch(err => {
      reject(err)
    })
  })
}

const post = (url, params, config = {}) => {
  return request(url, params, config, 'post')
}

const get = (url, params, config = {}) => {
  return request(url, params, config, 'get')
}
//3.匯出cancel token列表供全域性路由守衛使用
export {sources, post, get}

1.axios cancel token API2.存入需要取消的請求列表匯出給導航守衛使用3.router.js

...
import { sources } from '../service/request'
...
router.beforeEach((to, from, next) => {
  document.title = to.meta.title || to.name
    //路由發生變化時取消當前頁面網路請求
  sources.forEach(item => {
    item()
  })
  sources.length = 0
  next()
})

request.js完整程式碼:


// 引入網路請求庫 https://github.com/axios/axios

import axios from 'axios'
import store from '../store'
import router from '../router'

// axios.defaults.timeout = 10000
const requestList = []

axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'

axios.defaults.baseURL = process.env.BASE_URL
// 自定義攔截器
axios.interceptors.request.use((config) => {
  requestList.push(config.url)
  store.dispatch('changeGlobalState', {loading: true})
  const token = store.getters.userInfo.token
  if (token) {
    config.headers.token = token
  }
  return config
}, function (error) {
  return Promise.reject(error)
})

axios.interceptors.response.use(function (response) {
  requestList.splice(requestList.findIndex(item => item === response.config.url), 1)
  if (requestList.length === 0) {
    store.dispatch('changeGlobalState', {loading: false})
  }
  if (response.data.code === 900401) {
    window.$toast.error('認證失效,請重新登入!', 1000)
    router.push('/login')
  }
  return response
}, function (error) {
  requestList.length = 0
  store.dispatch('changeGlobalState', {loading: false})
  if (axios.isCancel(error)) {
    throw new axios.Cancel('cancel request')
  } else {
    window.$toast.error('網路請求失敗!', 1000)
  }
  return Promise.reject(error)
})

const CancelToken = axios.CancelToken
let sources = []

const request = function (url, params, config, method) {
  return new Promise((resolve, reject) => {
    axios[method](url, params, Object.assign(config, {
      cancelToken: new CancelToken(function executor (c) {
        sources.push(c)
      })
    })).then(response => {
      resolve(response.data)
    }, err => {
      reject(err)
    }).catch(err => {
      reject(err)
    })
  })
}

const post = (url, params, config = {}) => {
  return request(url, params, config, 'post')
}

const get = (url, params, config = {}) => {
  return request(url, params, config, 'get')
}

export {sources, post, get}

以上。