封装网络请求axios+ts

495 阅读2分钟

1、前期准备

下载相关依赖

yarn add axios 
or
npm install axios

yarn add antd(主要用于提示,可自行选择)
or
npm install antd(主要用于提示,可自行选择)

2、目录结构

/request/index.ts
/request/interceptors.ts

3、才艺表演

3.1 interceptors.ts
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { message } from 'antd'

// 请求拦截器
export const requestInterceptor = (instance: AxiosInstance) => {
    instance.interceptors.request.use(
        function (config) {
            CancelToken.addRequest(config)

            return config
        },
        function (error) {
            return Promise.reject(error)
        }
    )
}

type ResponseType<T = any> = {
    code?: string
    msg?: string
    data?: T
}

// 响应拦截器
export const responseInterceptor = (instance: AxiosInstance) => {
    instance.interceptors.response.use(
        function (response: AxiosResponse<ResponseType>) {
            const key: string = CancelToken.getKey(response.config)
            CancelToken.cencelRequest(key)
            if (response?.data?.code === '200') {
                return Promise.resolve(response.data)
            }
            businessStatus(response)
            return Promise.reject(response.data)
        },
        function (error) {
            if (error?.code === 'ERR_NETWORK') {
                message.error('网络错误,请检查网络')
            }
            if (error?.code === 'ECONNABORTED') {
                message.error('请求超时')
            }
            if (error?.code === 'ERR_CANCELED') {
                console.warn(`${error.message}请求已取消`)
            }
            if (error.response?.status) {
                browserStatus(error.response, error.config)
            }

            return Promise.reject(error)
        }
    )
}

// 业务状态处理
const businessStatus = (response: any) => {
    if (response.data.code === 'xxx') {
        // 指定code业务处理
        message.error(response.data.msg)
    } else {
        response.data.msg && message.error(response.data.msg)
    }
}

// 浏览器状态处理
const browserStatus = (response: any, config: any) => {
    switch (response.status) {
        // 未登录
        case 401:
            message.error('用户未登录')
            // 可自行处理跳登录页面
            break

        // 登录过期
        case 403:
            message.error('登录状态已过期')
            // 可自行处理跳登录页面
            break

        //资源不存在
        case 404:
            message.error(`${config.url} 资源不存在`)
            // 可自行处理跳404页面
            break

        // 服务端错误
        case 500:
            message.error('服务端错误')
            break

        // 其他status
        default:
            message.error('网络错误,请刷新后再试')
            break
    }
}

// 取消请求
export class CancelToken {
    // 存储每个请求的标识
    static requestList = new Map()

    // 白名单(不进行取消请求) 请求方式-接口(例如:get-/menus)
    static whiteList: Array<string> = []

    // 获取key
    static getKey(config: AxiosRequestConfig): string {
        return `${config.method}-${config.url}`
    }

    // 验证接口是否被加入白名单
    static verifyWhiteList(config: AxiosRequestConfig): boolean {
        const key: string = this.getKey(config)
        return this.whiteList.includes(key)
    }

    // 添加请求
    static addRequest(config: AxiosRequestConfig) {
        const key: string = this.getKey(config)
        config.cancelToken = new axios.CancelToken((cancel) => {
            // 若请求已存在(请求中)则取消上一次的请求
            if (this.requestList.has(key)) {
                // cancel(key) // 取消当前请求
                this.cencelRequest(key) // 取消上一次请求
            } else if (!this.requestList.has(key) && !this.verifyWhiteList(config)) {
                // 请求不存在并且不在白名单
                this.requestList.set(key, cancel)
            }
        })
    }

    // 取消单个请求
    static cencelRequest(key: string) {
        if (this.requestList.has(key)) {
            // 取消请求
            this.requestList.get(key)(key)
            // 删除当前请求
            this.requestList.delete(key)
        }
    }

    // 取消全部请求
    static cencelAllRequest() {
        // 遍历请求列表 全部取消
        for (const [url, cancel] of this.requestList) {
            cancel(url)
        }
        this.requestList.clear()
    }
}
3.2 index.ts(可创建多个axios实例)
import axios from 'axios'
import { requestInterceptor, responseInterceptor } from './interceptors'

const baseURL = 'http://xxxxxx1'
const baseURL2 = 'http://xxxxxx2'

// 初始化1
const instance = axios.create({
    baseURL: baseURL,
    timeout: 1000 * 20,
    withCredentials: true,
})
// 初始化2
const instance2 = axios.create({
    baseURL: baseURL2,
    timeout: 1000 * 20,
    withCredentials: true,
})

// 请求拦截器1
requestInterceptor(instance)
// 请求拦截器2
requestInterceptor(instance2)

// 响应拦截器1
responseInterceptor(instance)
// 响应拦截器2
responseInterceptor(instance2)

export default instance

4、如何使用

import axios from '@/request/index'

export enum Api {
    getList = '/api/getList',
    addForm = '/api/addForm',
    updateForm = '/api/updateForm',
    deleteUser = '/api/deleteUser',
}

// GET
export const getList = (params: any) => {
    return axios.get(Api.getList, { params })
}

// POST
export const addForm = (params: any) => {
    return axios.post(Api.addForm, params)
}

// PUT
export const updateForm = (params: any) => {
    return axios.put(Api.updateForm, params)
}

// DELETE
export const deleteUser = (params: any) => {
    return axios.delete(Api.deleteUser, { params })
}