ts + vue 封装 axios

安装 axios 、 qs

yarn add axios
yarn add qs
复制代码

封装 axios

封装 axios,由于 axios 是插件所以新建一个 plugins 文件夹来放置:

// ./src/plugins/axios/axiosConfigs.ts
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'
import store from '@/store';
import { ElMessage } from "element-plus";

// 创建axios的实例
const service = axios.create({
    // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL
    baseURL: process.env.NODE_ENV === 'production' ? `/` : '/api',

    headers: {
        'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
    },
    withCredentials: false, // 跨域请求时是否需要使用凭证
    timeout: 30000,
    // `validateStatus` 定义对于给定的 HTTP 响应状态码是 resolve 或 reject  promise 。
    validateStatus() {
        // `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
        // 使用 async-await,处理 reject 情况较为繁琐,所以全部返回 resolve,在业务代码中处理异常
        return true;
    },

    // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
    // transformResponse: [(data) => {
    //     if (typeof data === 'string' && data.startsWith('{')) {
    //         data = JSON.parse(data);
    //     }
    //     return data;
    // }]
});

// 添加请求拦截器
service.interceptors.request.use((config: AxiosRequestConfig) => {
    // console.log('发送请求之前', config.url);

    // 获取token,并将其添加至请求头中
    let token = store.state.user.token;
    if(token){
        config.headers.Authorization = token;
    }

    return config;
}, (error: any) => {
    console.log('发送请求错误', error.response, error.data);

    // 错误抛到业务代码
    error.data = {
        message: '服务器异常,请联系管理员!'
    };

    return Promise.reject(error);
});

//添加响应拦截器
service.interceptors.response.use((response: AxiosResponse) => {
    // console.log('响应拦截', response.status, response);

    /* 处理 http 错误,抛到业务代码 */
    const status = response.status;
    const decide = status < 200 || status >= 300;
    if (decide) {

        const message = showStatus(status);
        // console.log("处理 http 错误", message);
        if (typeof response.data === 'string') {
            response.data = { message };
        } else {
            response.data.message = message;
        }
        ElMessage({
            message,
            type: 'error',
            showClose: true
        })
        return Promise.reject(response.data);
    }

    return response;
}, (error: any) => {
    // console.log('请求错误', error, axios.isCancel(error), error.message);

    if (axios.isCancel(error)) {
        console.log('重复请求: ' + error.message);
    } else {
        const message = '请求超时或服务器异常,请检查网络或联系管理员!';
        ElMessage({
            message,
            type: 'error',
            showClose: true
        })
    }

    return Promise.reject(error);
});

const showStatus = (status: number) => {
    let message = '';
    switch (status) {
        case 400:
            message = '请求错误(400)';
            break;
        case 401:
            message = '未授权,请重新登录(401)';
            break;
        case 403:
            message = '拒绝访问(403)';
            break;
        case 404:
            message = '请求出错(404)';
            break;
        case 408:
            message = '请求超时(408)';
            break;
        case 500:
            message = '服务器错误(500)';
            break;
        case 501:
            message = '服务未实现(501)';
            break;
        case 502:
            message = '网络错误(502)';
            break;
        case 503:
            message = '服务不可用(503)';
            break;
        case 504:
            message = '网络超时(504)';
            break;
        case 505:
            message = 'HTTP版本不受支持(505)';
            break;
        default:
            message = `连接出错(${status})!`;
    }
    return message;
    // return `${message},请检查网络或联系管理员!`
};

export default service;
复制代码

设置请求及响应数据格式

设置响应数据格式,设置 getpost 等方法的格式:

// ./src/plugins/axios/types.ts
import { AxiosResponse, AxiosRequestConfig } from 'axios';

// 网络请求响应格式,T 是具体的接口返回类型数据
interface CustomSuccessData<T> {
    code: number;
    msg?: string;
    message?: string;
    data?: T;
    [keys: string]: any;
}

interface Get {
    <T>(url: string, config?: AxiosRequestConfig): Promise<CustomSuccessData<T>>;
}

interface Post {
    <T>(url: string, params?: string | object, config?: AxiosRequestConfig): Promise<CustomSuccessData<T>>;
}

// ... delete 等等

export {
    CustomSuccessData,
    Get,
    Post
}
复制代码

封装 axios 请求

封装 getpost 等方法,使用 request 统一调用:

// ./src/plugins/axios/request.ts
import service from '@/plugins/axios/axiosConfigs'
import { Get, Post } from './types'; // 接口泛型

// 封装 get 方法,类型为Get
const get: Get = async (url, config) => {
    const response = await service.get(url, { ...config});
    return response.data;
};

const post: Post = async (url, params, config) => {
    const response = await service.post(url, params, {...config});
    return response.data;
};

// ... delete 等等

// 使用 request 统一调用
const request = {
    get,
    post
};

export default request;
复制代码

接口配置

配置 api 接口,新增 api 文件夹:

// ./src/api/httpUrl.ts
const config: Api = {
    rootUrl: "http://localhost:8080/",
};

const httpApi: Api =  {
    // 测试接口
    banner: config.rootUrl + 'home/banner', // banner
    login: config.rootUrl + 'user/login', // 用户登录
}

export default httpApi
复制代码

请求接口配置:

// ./src/api/requestApi.ts
import request from '@/plugins/axios/request'; // axios 封装
import '@/utils/interfaces/AjaxResponse'; // 后端响应数据接口
import '@/utils/interfaces/AjaxRequest'; // 前端请求数据接口
import httpUrl from "./httpUrl"; // 接口 url
import qs from "qs"

// 获取 banner
const getBanner = async () => {
    return await request.get<Array<AjaxResponse.Banner>>(httpUrl.banner)
}

// 用户登录
const login = async (params: AjaxRequest.login) => {
    return await request.post<string>(httpUrl.login, qs.stringify(params))
}

const handleError = (err: any) => {
    // console.log("请求错误", err)
    throw err;
}

export {
    getBanner,
    login,
    handleError
}
复制代码

使用

import { getBanner, login, handleError } from '@/api/requestApi'; // 请求接口

export default class Home extends Vue {

    mounted(){
        console.log("mounted")

        const apiTest = async () => {

            // get 请求
            const banner = await getBanner().catch(handleError)
            console.log('banner', banner)

            // post 请求
            let logintest = await login({
                tel: '13192638728',
                password: '123456'
            }).catch(handleError)
            console.log("logintest", logintest)

        }

        apiTest()
    }
}
复制代码

错误测试

把请求头设置为 'Content-Type': 'application/json;charset=utf-8',请求 login 接口,报错:

throw.jpg

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享