一個完整實用的axios封裝


1.先引入

import axios from 'axios'
import qs from 'qs'
import router from '../router';
import store from '../store/index';

// 創建axios實例
var instance = axios.create({ timeout: 1000 * 12});
// 設置post請求頭
// instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; (可以不在這里封裝)

// 攔截器

instance.interceptors.request.use( config
=> { // 登錄流程控制中,根據本地是否存在token判斷用戶的登錄情況 // 但是即使token存在,也有可能token是過期的,所以在每次的請求頭 中攜帶token // 后台根據攜帶的token判斷用戶的登錄情況,並返回給我們對應的狀態 // 而后我們可以在響應攔截器中,根據狀態碼進行一些統一的操作。 const token = store.state.token; token && (config.headers.Authorization = token); return config; }, error => Promise.error(error) )
// 響應攔截器

instance.interceptors.response.use(

 // 請求成功

        res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res),
   // 請求失敗
        error => {
            const { response } = error;
            if (response) {
   // 請求已發出,但是不在2xx的范圍
                  errorHandle(response.status, response.data.message);
                  return Promise.reject(response);
             } else {
          // 處理斷網的情況
          // eg:請求超時或斷網時,更新state的network狀態
          // network狀態在app.vue中控制着一個全局的斷網提示組件的顯示隱藏
          // 關於斷網組件中的刷新重新獲取數據,會在斷網組件中說明
          store.commit('changeNetwork', false);
          }
   });

 

1.去掉了之前get和post方法的封裝,通過創建一個axios實例然后export default方法導出,這樣使用起來更靈活一些。

2.去掉了通過環境變量控制baseUrl的值。考慮到接口會有多個不同域名的情況,所以准備通過js變量來控制接口域名。這點具體在api里會介紹。

3.增加了請求超時,即斷網狀態的處理。說下思路,當斷網時,通過更新vuex中network的狀態來控制斷網提示組件的顯示隱藏。斷網提示一般會有重新加載數據的操作,這步會在后面對應的地方介紹。

4.公用函數進行抽出,簡化代碼,盡量保證單一職責原則。



// 一些方法的封裝

/*
* * 跳轉登錄頁 * 攜帶當前頁面路由,以期在登錄頁面完成登錄后返回當前頁面 */ const toLogin = () => { router.replace({ path: '/login', query: { redirect: router.currentRoute.fullPath } }); }

/**
* 請求失敗后的錯誤統一處理
* @param {Number} status 請求失敗的狀態碼
*/
   const errorHandle = (status, other) => {
       // 狀態碼判斷
       switch (status) {
       // 401: 未登錄狀態,跳轉登錄頁   
           case 401:
           toLogin();
           break;
       // 403 token過期
       // 清除token並跳轉登錄頁
           case 403:
           tip('登錄過期,請重新登錄');
           localStorage.removeItem('token');
           store.commit('loginSuccess', null);
           setTimeout(() => {
                 toLogin();
           }, 1000);
          break;
      // 404請求不存在
           case 404:
           tip('請求的資源不存在');
         break;
         default:
         console.log(other);
   }}

 
         

 

 

 
        

 

article.js:

/**
  * article模塊接口列表
  */

import base from './base'; // 導入接口域名列表
import axios from '@/utils/http'; // 導入http中創建的axios實例
import qs from 'qs'; // 根據需求是否導入qs模塊

const article = {
    // 新聞列表
    articleList () {
        return axios.get(`${base.sq}/topics`);
    },
    // 新聞詳情,演示
    articleDetail (id, params) {
        return axios.get(`${base.sq}/topic/${id}`, {
            params: params
        });
    },
    // post提交
    login (params) {
        return axios.post(`${base.sq}/accesstoken`, qs.stringify(params));
    }
    // 其他接口…………
}

export default article;

 

index.js:

這里這里呢新建了一個api文件夾,里面有一個index.js和一個base.js,以及多個根據模塊划分的接口js文件。index.js是一個api的出口,base.js管理接口域名,其他js則用來管理各個模塊的接口。

/**
  * api接口的統一出口
  */
// 文章模塊接口
import article from '@/api/article';
// 其他模塊的接口……

// 導出接口
export default {
    article,
    // ……
}

 

base.js:

/**
  * 接口域名的管理
  */
const base = {
    sq: 'https://xxxx111111.com/api/v1',
    bd: 'http://xxxxx22222.com/api'
}

export default base;

.請求的配置更靈活,你可以針對某個需求進行一個不同的配置。關於配置的優先級,axios文檔說的很清楚,這個順序是:在 lib/defaults.js 找到的庫的默認值,然后是實例的 defaults 屬性,最后是請求的 config 參數。后者將優先於前者。

最后,為了方便api的調用,我們需要將其掛載到vue的原型上。在main.js中

import Vue from 'vue'
import App from './App'
import router from './router' // 導入路由文件
import store from './store' // 導入vuex文件
import api from './api' // 導入api接口

Vue.prototype.$api = api; // 將api掛載到vue的原型上

在頁面中這樣調用接口:

methods: {
    onLoad(id) {
        this.$api.article.articleDetail(id, {
            api: 123
        }).then(res=> {
            // 執行某些操作
        })
    }
}

再提一下斷網的處理,這里只做一個簡單的示例

<template>
    <div id="app">
        <div v-if="!network">
            <h3>我沒網了</h3>
            <div @click="onRefresh">刷新</div>
        </div>
        <router-view/>
    </div>
</template>

<script>
    import { mapState } from 'vuex';
    export default {
        name: 'App',
        computed: {
            ...mapState(['network'])
        },
        methods: {
            // 通過跳轉一個空頁面再返回的方式來實現刷新當前頁面數據的目的
            onRefresh () {
                this.$router.replace('/refresh')
            }
        }
    }
</script>
// refresh.vue
beforeRouteEnter (to, from, next) {
    next(vm => {
        vm.$router.replace(from.fullPath)
    })
}

至此全部完結。文章參考博客喵容 - 和你一起描繪生活

 

這下面貼一下自己封裝的。比上面稍簡單些,靈活度不是很高,但適合小白,初學者配置使用,算是很實用吧。

import axios from 'axios'
// import qs from 'qs'
axios.interceptors.request.use(config => {
  let append = document.getElementsByName('body')
  append.innerHTML = '<img style="position:fixed;\n' +
                      ' left:47%;\n' +
                      ' top:40%;\n' +
                      ' transform: translateY(-50%),translateX(-50%);"' +
                      ' src="../../static/img/loading2.gif"/>'
  return config
}, err => {
  return Promise.resolve(err)
})

let base= ‘’   // 接口域名

export const request = (url, params,method,Func,isJson) => {
  // let _this = this;
  axios({
    method: method,
    url: `${base}${url}`,
    data: method=== 'post'? params: '',
    transformRequest: [function (data) {
      if(isJson === 1) {
        // debugger       // 判斷是否json格式或者是表單提交形式
        return JSON.stringify(data)
      }
      let ret = ''
      for (let it in data) {
        ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
      }
      return ret         // 便於直接取到內部data
    }],
  headers: {
      // 認證和請求方式
      'Content-Type':  isJson === 1 ? 'application/json' : 
      'application/x-www-form-urlencoded',
      'authorization':sessionStorage.getItem('principal'),
      'token':sessionStorage.getItem('token')
    },
    params: method=== 'get'? params: '',
  }).then(data=>{
    console.log(data)
    if (data.data.code === 200) {
      Func(data.data.data)
    }else if(data.data.code === 406){
      alert(data.data.message)
    }else if(data.data.code === 401){
     window.location.href=''//上線用這個地址
    //  window.location.href='/'
    }else if(data.data.code === 400 || data.data.code === 505 || data.data.code === 404|| data.data.code === 500){
      alert('網絡異常')
    }else if(data.data.code === 4011){
      // window.location.href = '' //本地
      window.location.href = '' //線上
    }else if(data.data.code === 4012){
      console.log(1111)
      request('token/refresh',{
        'authorization': sessionStorage.getItem('principal'),
        'refreshToken': sessionStorage.getItem('refreshToken')
      },'get',(res)=>{
        //緩存新的token
        console.log(res)
        let token = res.token;
        let principal = res.principal;
        let refreshToken = res.refreshToken;
        sessionStorage.setItem("token", token);
        sessionStorage.setItem("principal", principal);
        sessionStorage.setItem("refreshToken", refreshToken);
         request(url, params,method,Func);
      });
    }
  })
}

// post
export const postRequest = (url, params,Func,isJson) => {
  request(url, params,'post',Func,isJson)
}

// uploadFileRequest  圖片上傳
export const uploadFileRequest = (url, params) => {
  return axios({
    method: 'post',
    url: `${base}${url}`,
    data: params,
    headers: {
      'Content-Type': 'multipart/form-data',
      'authorization':sessionStorage.getItem('principal'),
      'token':sessionStorage.getItem('token')
      // 'authorization':'admin',
      // 'token':'740a1d6be9c14292a13811cabb99950b'
    }
  })
}

// get 

export const getRequest = (url, params,Func,isJson) => {
  request(url, params,'get',Func,isJson)
}

main.js 引入

import {getRequest,postRequest} from './api/http'
Vue.prototype.$getRequest = getRequest;
Vue.prototype.$postRequest = postRequest;

token失效自動刷新,請看我另篇博客:https://www.cnblogs.com/panax/p/13393459.html

至此結束了。相比配置只有兩個文件,比較清晰。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM