axios 怎麼封裝,才能提升效率?

大家好,我是若川。今天分享一篇 axios 封裝的文章。學習源碼系列面試年度總結JS 基礎系列。

作爲前端開發者,每個項目基本都需要和後臺交互,目前比較流行的 ajax 庫就是 axios 了,當然也有同學選擇 request 插件,這個蘿蔔白菜,各有所愛了。目前雖然 axios 有 config、interceptor 和各個請求方式,但是針對一個大型的項目,我們還是需要做二次封裝才能快速提升開發效率!

今天我們針對 axios 庫做二次封裝,看看是否有簡化我們的開發工作。

創建項目

  vue create axios-demo

創建目錄

  // 進入到項目空間中
  cd axios-demo
  // 在src下創建api目錄

創建三個文件 (index.js/interceptor.js/request.js)

/**
 * index.js
 * api地址管理
 */
export default {
    login:'/user/login',
    getInfo:'/user/getInfo'
}

index.js 實際上和 axios 封裝沒有關係,因爲它也屬於 API 這一層,所以我一起創建了,我個人習慣把項目所有 url 抽取到這裏集中管理。

封裝 interceptor

interceptor 作用就是攔截,可以針對請求參數和響應結果進行攔截處理,一般在項目當中,我們主要會針對接口常規報錯、網絡報錯、系統超時、權限認證等做攔截處理。

此處我們對通過 create 創建實例,設置 baseUrl,timeout,然後在設置 request 和 response 的攔截。

/**
 * 生成基礎axios對象,並對請求和響應做處理
 * 前後端約定接口返回解構規範
 * {
 *    code:0,
 *    data:"成功",
 *    message:""
 * }
 */
import axios from 'axios'
import { Message } from 'element-ui'

// 創建一個獨立的axios實例
const service = axios.create({ 
    // 設置baseUr地址,如果通過proxy跨域可直接填寫base地址
    baseURL: '/api',
    // 定義統一的請求頭部
    headers: {
        post: {
            "Content-Type""application/x-www-form-urlencoded;charset=UTF-8"
        }
    },
    // 配置請求超時時間
    timeout: 10000, 
    // 如果用的JSONP,可以配置此參數帶上cookie憑證,如果是代理和CORS不用設置
    withCredentials: true
});
// 請求攔截
service.interceptors.request.use(config ={
    // 自定義header,可添加項目token
    config.headers.token = 'token';
    return config;
});
// 返回攔截
service.interceptors.response.use((response)=>{
    // 獲取接口返回結果
    const res = response.data;
    // code爲0,直接把結果返回回去,這樣前端代碼就不用在獲取一次data.
    if(res.code === 0){
        return res;
    }else if(res.code === 10000){
        // 10000假設是未登錄狀態碼
        Message.warning(res.message);
        // 也可使用router進行跳轉
        window.location.href = '/#/login';
        return res;
    }else{
        // 錯誤顯示可在service中控制,因爲某些場景我們不想要展示錯誤
        // Message.error(res.message);
        return res;
    }
},()=>{
    Message.error('網絡請求異常,請稍後重試!');
});
export default service;

如果是 CORS/JSONP 需要區分環境,可通過process.env.NODE_ENV來選擇使用哪個地址。如果使用的是代理,則 Vue 項目需要在 vue.config.js 中的 proxy 裏面增加環境判斷。

process.env.NODE_ENV=== "production" ? "http://www.prod.com/api" : "http://localhost/:3000/api"

以上是針對 interceptor 做的二次封裝,上面我們沒有把常規錯誤放進去,是因爲我們想要在後期控制錯誤是否顯示,所以我們會在 request 中處理。

封裝 axios

創建 request 文件,針對 axios 做適合業務發展的封裝,很多時候架構師做公共機制都是爲了迎合自身項目需要,而並非一味求大做全,所以這個大家要適當調整,比如我們只用 get/post 請求。

/**
 * request.js
 * 通過promise對axios做二次封裝,針對用戶端參數,做靈活配置
 */
import { Message,Loading } from 'element-ui';
import instance from './interceptor'

/**
 * 核心函數,可通過它處理一切請求數據,並做橫向擴展
 * @param {url} 請求地址
 * @param {params} 請求參數
 * @param {options} 請求配置,針對當前本次請求;
 * @param loading 是否顯示loading
 * @param mock 本次是否請求mock而非線上
 * @param error 本次是否顯示錯誤
 */
function request(url,params,options={loading:true,mock:false,error:true},method){
    let loadingInstance;
    // 請求前loading
    if(options.loading)loadingInstance=Loading.service();
    return new Promise((resolve,reject)=>{
        let data = {}
        // get請求使用params字段
        if(method =='get')data = {params}
        // post請求使用data字段
        if(method =='post')data = {data:params}
        // 通過mock平臺可對局部接口進行mock設置
        if(options.mock)url='http://www.mock.com/mock/xxxx/api';
        instance({
            url,
            method,
            ...data
        }).then((res)=>{
            // 此處作用很大,可以擴展很多功能。
            // 比如對接多個後臺,數據結構不一致,可做接口適配器
            // 也可對返回日期/金額/數字等統一做集中處理
            if(res.status === 0){
                resolve(res.data);
            }else{
                // 通過配置可關閉錯誤提示
                if(options.error)Message.error(res.message);
                reject(res);
            }
        }).catch((error)=>{
            Message.error(error.message)
        }).finally(()=>{
            loadingInstance.close();
        })
    })
}
// 封裝GET請求
function get(url,params,options){
    return request(url,params,options,'get')
}
// 封裝POST請求
function post(url,params,options){
    return request(url,params,options,'post')
}
export default {
    get,post
}

request.js 主要針對 axios 做二次封裝,目的同樣是爲了攔截所有前端請求,這樣可以做前端 loading 效果、mock、錯誤攔截、錯誤彈框顯示、數據適配、參數適配、環境適配等工作。

接下來,我們看下如何使用

// 導入插件
import request from './api/request'
// 在原型上擴展,這樣不用在每個頁面都導入request
Vue.prototype.request = request;
  this.request.get('/login',{userName:'admin',userPwd:'admin'}).then((res={})=>{
        // 此處只接收成功數據,失敗數據不返回
  }).catch(()=>{
      // catch 可以不要,如果想要捕獲異常,就加上去
  })

如果不做二次封裝,我們很難實現以上功能點,這是在公司做了很多箇中型後臺系統後,總結出來的一些個人經驗,我相信您看了之後,會有一些啓發和幫助,如果有疑問或者不夠完善可以留言或聯繫我,我進行修訂。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/8qbSVehFyiVSpBURZYkiNA