1. 程式人生 > 其它 >把axios封裝為vue外掛使用

把axios封裝為vue外掛使用

前言

自從Vue2.0推薦大家使用 axios 開始,axios 被越來越多的人所瞭解。使用axios發起一個請求對大家來說是比較簡單的事情,但是axios沒有進行封裝複用,專案越來越大,引起的程式碼冗餘。就會非常麻煩的一件事。所以本文會詳細的跟大家介紹,如何封裝請求,並且在專案元件中複用請求。有需要的朋友可以做一下參考。

封裝的基本要求

  • 統一 url 配置
  • 統一 api 請求
  • request (請求)攔截器,例如:帶上token等,設定請求頭
  • response (響應)攔截器,例如:統一錯誤處理,頁面重定向等
  • 根據需要,結合 Vuex 做全域性的loading動畫,或者錯誤處理
  • 將 axios 封裝成 Vue 外掛使用

檔案結構

在src目錄下新建 http 資料夾

config.js ====> axios的預設配置
api.js   ====> 二次封裝axios,攔截器等
interface.js ====> 請求介面檔案
index.js ====> 將axios封裝成外掛

config.js

完整配置請參考 axios 的官方文件

export default {
  method: 'get',
  // 基礎url字首
  baseURL: 'https://www.example.com/api',
  // 請求頭資訊
  headers: {
    'Content-Type': 'application/json;charset=UTF-8'
  },
  
// 引數 data: {}, // 設定超時時間 timeout: 10000, // 攜帶憑證 withCredentials: true, // 返回資料型別 responseType: 'json' }

api.js

import axios from 'axios';   // 注意先安裝哦
import config from './config.js';   // 倒入預設配置
import qs from 'qs';   // 序列化請求資料,視服務端的要求
import Cookies from "js-cookie";
import router from '@/router'

//
使用vuex做全域性loading時使用 // import store from '@/store' export default function $axios(options) { return new Promise((resolve, reject) => { const instance = axios.create({ baseURL: config.baseURL, headers: {}, transformResponse: [function (data) { }] }) // request 攔截器 instance.interceptors.request.use( config => { let token = Cookies.get('markToken') // 1. 請求開始的時候可以結合 vuex 開啟全屏 loading 動畫 // console.log(store.state.loading) // console.log('準備傳送請求...') // 2. 帶上token if (token) { config.headers.accessToken = token } else { // 重定向到登入頁面 router.push('/login') } // 3. 根據請求方法,序列化傳來的引數,根據後端需求是否序列化 if (config.method === 'post') { if (config.data.__proto__ === FormData.prototype || config.url.endsWith('path') || config.url.endsWith('mark') || config.url.endsWith('patchs') ) { } else { config.data = qs.stringify(config.data) } } return config }, error => { // 請求錯誤時 console.log('request:', error) // 1. 判斷請求超時 if (error.code === 'ECONNABORTED' && error.message.indexOf('timeout') !== -1) { console.log('timeout請求超時') // return service.request(originalRequest);//再重複請求一次 } // 2. 需要重定向到錯誤頁面 const errorInfo = error.response console.log(errorInfo) if (errorInfo) { //error =errorInfo.data //頁面那邊catch的時候就能拿到詳細的錯誤資訊,看最下邊的Promise.reject const errorStatus = errorInfo.status; // 404 403 500 ... router.push({ path: `/error/${errorStatus}` }) } return Promise.reject(error) // 在呼叫的那邊可以拿到(catch)你想返回的錯誤資訊 } ) // response 攔截器 instance.interceptors.response.use( response => { let data; // IE9時response.data是undefined,因此需要使用response.request.responseText(Stringify後的字串) if (response.data == undefined) { data = JSON.parse(response.request.responseText) } else { data = response.data } // 根據返回的code值來做不同的處理(和後端約定) switch (data.code) { case 1: console.log(data.desc) break; case 0: store.commit('changeState') // console.log('登入成功') default: } // 若不是正確的返回code,且已經登入,就丟擲錯誤 // const err = new Error(data.desc) // err.data = data // err.response = response // throw err return data }, err => { if (err && err.response) { switch (err.response.status) { case 400: err.message = '請求錯誤' break case 401: err.message = '未授權,請登入' break case 403: err.message = '拒絕訪問' break case 404: err.message = `請求地址出錯: ${err.response.config.url}` break case 408: err.message = '請求超時' break case 500: err.message = '伺服器內部錯誤' break case 501: err.message = '服務未實現' break case 502: err.message = '閘道器錯誤' break case 503: err.message = '服務不可用' break case 504: err.message = '閘道器超時' break case 505: err.message = 'HTTP版本不受支援' break default: } } console.error(err) return Promise.reject(err) // 返回介面返回的錯誤資訊 } ) // 請求處理 instance(options).then(res => { resolve(res) return false }).catch(error => { reject(error) }) }) }

interface.js

import axios from './api'

/* 將所有介面統一起來便於維護
 * 如果專案很大可以將 url 獨立成檔案,介面分成不同的模組
 */

// 單獨匯出
export const query = () => {
  return axios({
    url: '/query',
    method: 'get'
  })
}

export const list = (id) => {
  return axios({
    url: `/list${id}`,
    method: 'get'
  })
}

export const upload = data => {
  return axios({
    url: '/upload',
    method: 'post',
    data
  })
}

// 預設全部匯出
export default {
  query,
  list,
  upload
}

index.js

封裝成 Vue 外掛

// 匯入所有介面
import apiList from './interface'
const install = Vue => {
    if (install.installed) 
        return;
    install.installed = true;

    Object.defineProperties(Vue.prototype, {
        // 注意哦,此處掛載在 Vue 原型的 $api 物件上
        $api: {
            get() {
                return apiList
            }
        }
    })
}

export default install

使用

到此為止,萬事俱備就差用了,在 mian.js 中做如下操作:

import api from './http/index'
Vue.use(api)
// 此時可以直接在 Vue 原型上呼叫 $api 了

在 vue 中使用

// List.vue

...
this.$api.list(id).then(res => {
     if (res.rc === 0) {
          this.pageList = res.data.item
      } else {
        this.$Message.info(res.desc);
      }
     })
     .catch(error => {
        this.$Message.info(error);
      })
...

總結

  • 以上二次封裝較為全面,基本完成了我們之前的需求
  • 在錯誤的處理上還需要與後端協定好返回值,做具體的約定