Axios學習(5)---axios請求的封裝與使用

Axios學習(5)—axios請求的封裝與使用

思路分析

axios 請求的封裝,無非是爲了方便代碼管理,我們可以使用抽離拆分的思想,將不同功能模塊的接口處理成不同的模塊,然後封裝一個方法,專門用於數據交互。

第一步:新建 src/service/contactApi.js 文件

const CONTACT_API = {
    // 獲取聯繫人列表
    getContactList:{
        method:'get',
        url:'/contactList'
    },
    // 新建聯繫人 form-data
    newContactForm:{
        method:'post',
        url:'/contact/new/form'
    },
    // 新建聯繫人 application/json
    newContactJson:{
        method:'post',
        url:'/contact/new/json'
    },
    // 編輯聯繫人
    editContact:{
        method:'put',
        url:'/contact/edit'
    },
    // 刪除聯繫人
    delContact:{
        method:'delete',
        url:'/contact'
    }
}
export default CONTACT_API

備註:該文件的用途只有一個,定義不同的接口請求信息(包含 method、***url***等)並導出使用。當接口增加或者刪除的時候,只需要定義在該文件中即可。


第二步:新建 src/service/http.js 文件

import axios from 'axios'
import service from './contactApi'
import { Toast } from 'vant'
// service 循環遍歷輸出不同的請求方法
let instance = axios.create({
    baseURL: 'http://localhost:9000/api',
    timeout: 1000
})
const Http = {}; // 包裹請求方法的容器

// 請求格式/參數的統一
for (let key in service) {
    let api = service[key]; // url method
    // async 作用:避免進入回調地獄
    Http[key] = async function(
        params, // 請求參數 get:url,put,post,patch(data),delete:url
        isFormData = false, // 標識是否是form-data請求
        config = {} // 配置參數
    ) {
        let newParams = {}

        //  content-type是否是form-data的判斷
        if (params && isFormData) {
            newParams = new FormData()
            for (let i in params) {
                newParams.append(i, params[i])
            }
        } else {
            newParams = params
        }
        // 不同請求的判斷
        let response = {}; // 請求的返回值
        if (api.method === 'put' || api.method === 'post' || api.method === 'patch') {
            try {
                response = await instance[api.method](api.url, newParams, config)
            } catch (err) {
                response = err
            }
        } else if (api.method === 'delete' || api.method === 'get') {
            config.params = newParams
            try {
                response = await instance[api.method](api.url, config)
            } catch (err) {
                response = err
            }
        }
        return response; // 返回響應值
    }
}

// 攔截器的添加
// 請求攔截器
instance.interceptors.request.use(config => {
        // 發起請求前做些什麼
        Toast.loading({
            mask: false,
            duration: 0, // 一直存在
            forbidClick: true, // 禁止點擊
            message: '加載中...'
        })
        return config
    }, () => {
        // 請求錯誤
        Toast.clear()
        Toast('請求錯誤,請求稍後重試')
    })
    // 響應攔截器
instance.interceptors.response.use(res => {
    // 請求成功
    Toast.clear()
    return res.data
}, () => {
    Toast.clear()
    Toast('請求錯誤,請求稍後重試')
})

export default Http

具體的思路步驟如下:

  1. 首先,我們引入contactApi.js文件,別名定義爲 service

    import service from './contactApi'
    
  2. 定義新的 axios 實例,針對當前功能模塊聯繫人列表管理 contactList ,配置baseURL基礎域名、timeout請求超時時間等等,區別於其他功能模塊。

    let instance = axios.create({
        baseURL: 'http://localhost:9000/api',
        timeout: 1000
    })
    
  3. 定義 http 作爲請求方法的容器,配置對應的參數(即請求方法中的其他信息,比如 headerscontent-typetoken等等)。需要注意的是,在其中我們要區分 content-type的形式有兩種:form-dataapplication/json,它們的參數配置不同,form-data 形式的參數,我們需要定義 Formdata 對象。具體如下:

    let newParams = {}
    //  content-type是否是form-data的判斷
    if (params && isFormData) {
        newParams = new FormData()
        for (let i in params) {
            newParams.append(i, params[i])
        }
    } else {
        newParams = params
    }
    

    溫馨提示:其中 isFormData 定義爲 Boolean 變量,用於標識是否爲 FormData 形式。

  4. 根據不同的請求方式,發起網絡請求,並導出返回值。

    // 不同請求的判斷
    let response = {}; // 請求的返回值
    if (api.method === 'put' || api.method === 'post' || api.method === 'patch') {
        try {
            response = await instance[api.method](api.url, newParams, config)
        } catch (err) {
            response = err
        }
    } else if (api.method === 'delete' || api.method === 'get') {
        config.params = newParams
        try {
            response = await instance[api.method](api.url, config)
        } catch (err) {
            response = err
        }
    }
    return response; // 返回響應值
    

    注意:對於不同方法的區別在於:getdelete 的參數在 config 中配置,而不是使用 params

  5. 設置請求攔截器與響應攔截器

    // 攔截器的添加
    // 請求攔截器
    instance.interceptors.request.use(config => {
            // 發起請求前做些什麼
            Toast.loading({
                mask: false,
                duration: 0, // 一直存在
                forbidClick: true, // 禁止點擊
                message: '加載中...'
            })
            return config
        }, () => {
            // 請求錯誤
            Toast.clear()
            Toast('請求錯誤,請求稍後重試')
        })
        // 響應攔截器
    instance.interceptors.response.use(res => {
        // 請求成功
        Toast.clear()
        return res.data
    }, () => {
        Toast.clear()
        Toast('請求錯誤,請求稍後重試')
    })
    
  6. 導出src/service/http.js文件,用於其他地方的引入。

    export default Http
    

第三步:在入口文件中導入 http.js ,並掛載到 vue 原型上。

import Http from './service/http'
// 把Http掛載到Vue實例上
Vue.prototype.$Http = Http

第四步:在組件中使用封裝的請求

//   獲取聯繫人列表
async getList(){
    let res = await this.$Http.getContactList()
    this.list = res.data
},

注意:在使用的時候,我們需要結合 asyncawait 才能正確使用。具體的使用方法是:

  1. 在定義的網絡請求函數前增加 async 標識。
  2. 在接收請求返回數據的時候,增加 await 標識。
  3. 提示:在上面函數中,只有在 res 拿到後纔會執行 this.list = res.data; 相當於在對應的 then 中執行的語句,避免了回調地獄。

總結:

在進行項目開發的時候,我們需要對網絡請求的方法進行封裝,可以有效地減少後期代碼維護的難度,建議開發者根據不同的功能模塊進行拆分,方便後期代碼問題的定位。另外,也能實現代碼的低耦合,避免出現更多的重複代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章