axios 是一個基於 promise 的 HTTP 庫,能夠用在瀏覽器和 node.js 中。
在前端框架中的應用也是特別普遍,無論是vue仍是react,都有不少項目用axios做爲網絡請求庫。
我在最近的幾個項目中都有使用axios,並基於axios根據常見的業務場景封裝了一個通用的request服務。前端
業務場景:vue
定義全局的默認配置node
axios.defaults.timeout = 10000 //超時取消請求 axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8' axios.defaults.baseURL = process.env.BASE_URL //掛載在process下的環境常量,在我另外一篇文章有詳細說明
如何定義多環境常量react
自定義配置(很是見業務場景,僅做介紹)ios
// 建立實例時設置配置的默認值 var instance = axios.create({ baseURL: 'https://api.another.com' }); // 在實例已建立後修改默認值 instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
優先級:自定義配置 > 默認配置git
請求攔截器及取消重複請求github
// 請求列表 const requestList = [] // 取消列表 const CancelToken = axios.CancelToken let sources = {} axios.interceptors.request.use((config) => { //將請求地址及參數做爲一個完整的請求 const request = JSON.stringify(config.url) + JSON.stringify(config.data) config.cancelToken = new CancelToken((cancel) => { sources[request] = cancel }) //1.判斷請求是否已存在請求列表,避免重複請求,將當前請求添加進請求列表數組; if(requestList.includes(request)){ sources[request]('取消重複請求') }else{ requestList.push(request) //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.請求攔截器中將全部請求添加進請求列表變量,爲取消請求及loading狀態管理作準備;當請求列表已存在當前請求則不響應該請求。
2.請求一旦開始,就能夠開啓動畫加載效果。
3.用戶登陸後能夠在請求頭中攜帶token作權限校驗使用。json
響應攔截器axios
axios.interceptors.response.use(function (response) { // 1.將當前請求中請求列表中刪除 const request = JSON.stringify(response.config.url) + JSON.stringify(response.config.data) requestList.splice(requestList.findIndex(item => item === request), 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之外都歸爲網絡請求失敗segmentfault
const request = function (url, params, config, method) { return new Promise((resolve, reject) => { axios[method](url, params, Object.assign({}, config)).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 API
2.存入須要取消的請求列表導出給導航守衛使用
3.路由發生變化的時候取消當前頁面尚未返回結果的請求,在複雜的頁面中請求可能會有不少個,增長取消請求的功能可讓頁面切換的時候不卡頓。
/src/router.js
... import { sources } from '../service/request' ... router.beforeEach((to, from, next) => { document.title = to.meta.title || to.name //路由發生變化時取消當前頁面網絡請求 Object.keys(sources).forEach(item => { sources[item]('取消前頁面請求') }) for (var key in sources) { delete sources[key] } next() })
// 引入網絡請求庫 https://github.com/axios/axios import axios from 'axios' import store from '../store' import router from '../router' // 請求列表 const requestList = [] // 取消列表 const CancelToken = axios.CancelToken let sources = {} // axios.defaults.timeout = 10000 axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8' axios.defaults.baseURL = process.env.BASE_URL axios.interceptors.request.use((config) => { const request = JSON.stringify(config.url) + JSON.stringify(config.data) config.cancelToken = new CancelToken((cancel) => { sources[request] = cancel }) if(requestList.includes(request)){ sources[request]('取消重複請求') }else{ requestList.push(request) 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) { const request = JSON.stringify(response.config.url) + JSON.stringify(response.config.data) requestList.splice(requestList.findIndex(item => item === request), 1) if (requestList.length === 0) { store.dispatch('changeGlobalState', {loading: false}) } if (response.data.code === 900401) { window.ELEMENT.Message.error('認證失效,請從新登陸!', 1000) router.push('/login') } return response }, function (error) { if (axios.isCancel(error)) { requestList.length = 0 store.dispatch('changeGlobalState', {loading: false}) throw new axios.Cancel('cancel request') } else { window.ELEMENT.Message.error('網絡請求失敗', 1000) } return Promise.reject(error) }) const request = function (url, params, config, method) { return new Promise((resolve, reject) => { axios[method](url, params, Object.assign({}, config)).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') } export {sources, post, get}
以上。