在这里插入图片描述

一、安装axios

Axios 中文文档 (https://www.axios-http.cn/)
使用安装命令,将axios安装到项目上,当前文章案例采用vite3+vue3+typescript项目

npm install axios

先来个文件目录结构吧
你好! 这是你第一次使用 **Markdown编辑器** 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

二、创建axios实例

// 配置新建一个 axios 实例
const service = axios.create({
    baseURL: import.meta.env.MODE == 'development' ? '' : (import.meta.env.VITE_API_URL || ''),
    timeout: 15000,
    headers: { 'Content-Type': 'application/json' },
});

  简单创建一个axios实例,
baseURL:请求接口的地址,一般在开发环境会配置代理,baseURL可以为空,生产环境中不需要代理,可以直接写后端接口地址,这里使用了环境变量import.meta.env.VITE_API_URL,当打包上线的时候,只需要更改.env文件的VITE_API_URL,不需要找到当前这个文件来修改,而且开发跟线上用的是不同地址时,也很方便,只需设置环境变量的地址就行了
在这里插入图片描述
补充一个环境变量的知识 vite.config.ts里面使用环境变量

三、请求拦截器

  请求拦截器的作用是在请求发送前进行一些操作,例如在每个请求时携带上token,追加参数,对参数配合后端做加密处理等等

// 添加请求拦截器
// 添加请求拦截器
service.interceptors.request.use((config) => {
    // 在发送请求之前做些什么
    // 例如追加token
    let token = sessionStorage.get('token');
    if (token) {    // token存放到请求头中
        (config.headers as any).common['Authorization'] = token;
    }

    // post请求参数在 config.data里,get请求在config.params里面
    let type: 'params' | 'data' = config.method == 'post' ? 'data' : 'params'

    // 可以在里面追参数,例如添加一个时间戳time
    // config[type] = {
    //     ...config[type],
    //     time: Date.now()
    // }

    return config;
}, (error) => {
    // 对请求错误做些什么
    return Promise.reject(error);
});

四、响应拦截器

  响应拦截器的作用是在接收到响应后进行一些操作,例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页。

// 添加响应拦截器
service.interceptors.response.use((response) => {
    // 对响应数据做点什么

    // 例如登录失效的操作
    // const res = response.data;
    // if (res.code && res.code == 403) {
    //     // `token` 过期或者账号已在别处登录
    //     sessionStorage.clear(); // 清除浏览器全部临时缓存
    //     window.location.href = '/'; // 去登录页
    //     ElMessageBox.alert('账号已过期,请重新登录', '提示', {})
    //         .then(() => { })
    //         .catch(() => { });
    //     return Promise.reject(service.interceptors.response);
    // } else {
    //     return response.data;
    // }
    return response.data;      // 这里返回 response.data,默认返回整个axios对象,后端返回的在response.data包起来了
}, (error) => {
    // 对响应错误做点什么
    // 根据相应的error数据去写提示
    if (error.message.indexOf('timeout') != -1) {
        ElMessage.error('网络超时');
    } else if (error.message == 'Network Error') {
        ElMessage.error('网络连接错误');
    } else {
        ElMessage.error(error.response.status + ',' + error.response.statusText);
        //    if (error.response.data)  else ElMessage.error('接口路径找不到');
    }
    return Promise.reject(error);
});

这里用的时Element-plus的提示组件,可以换成自己项目的提示组件

五、 封装post、get等方法

先与后端约定好返回的一个大致格式,如:code,msg,data等等

/**
 * 跟后端约定返回的数据格式
 */
interface ResponseData<T> {
    code: number;   //  状态码,示例:-  200 : 成功
    msg: string;    // 返回文字描述,示例:-  提交成功
    data: T;    // 泛型数据,定义接口时传过来类型
}

简单封装一下接口,最后设置返回类型为Promise<ResponseData<T>>

/**
 * @method post请求
 * @param {string} url 请求接口路由地址
 * @param {any} [data] 接口参数
 * @param {any} [config] 请求头部配置信息
 * @returns {Promise<ResponseData<T>>}
 */
const post = <T = any>(url: string, data?: any, config?: any): Promise<ResponseData<T>> => {
    return service.post(url, data, { ...config })
}

/**
 * @method get请求
 * @param {string} url 请求接口路由地址
 * @param {any} [data] 接口参数
 * @param {any} [config] 请求头部配置信息
 * @returns {Promise<ResponseData<T>>}
 */
const get = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ResponseData<T>> => {
    return service.get(url, {
        params: data,
        ...config
    })
}

/**
 * @method del删除
 * @param {string} url 请求接口路由地址
 * @param {any} [data] 接口参数
 * @param {any} [config] 请求头部配置信息
 * @returns {Promise<ResponseData<T>>}
 */
const del = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ResponseData<T>> => {
    return service.delete(url, {
        params: data,
        ...config
    })
}
/**
 * @method put请求
 * @param {string} url 请求接口路由地址
 * @param {any} [data] 接口参数
 * @param {any} [config] 请求头部配置信息
 * @returns {Promise<ResponseData<T>>}
 */
const put = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ResponseData<T>> => {
    return service.put(url, data, { ...config })
}

调用方法

登录接口/src/api/login.ts

import { post } from '@/utils/http/request';

/**
 * 登录 - 请求参数
 */
interface LoginData {
    user: string;
    password: string;
}
/**
 * 登录 - 接口响应数据
 */
interface LoginDataResponse {
    token: string;
    user_info: {
        name: string;
        role_id: string;
    };
}

/**
 * 登录api
 * @method getCode 获取验证码
 * @method signIn 登录
 */
export const LoginApi = {

    signIn: (data: LoginData) => post<LoginDataResponse>("/api/admin_auth/login", data),

}

在login.vue文件里面调用
在这里插入图片描述
在这里插入图片描述

六、完整代码

import axios, { AxiosRequestConfig } from 'axios';
import { ElMessage, ElMessageBox } from 'element-plus';


// 配置新建一个 axios 实例
const service = axios.create({
    baseURL: import.meta.env.MODE == 'development' ? '' : (import.meta.env.VITE_API_URL || ''),
    timeout: 15000,
    headers: { 'Content-Type': 'application/json' },
});

// 添加请求拦截器
service.interceptors.request.use((config) => {
    // 在发送请求之前做些什么
    // 例如追加token
    let token = sessionStorage.get('token');
    if (token) {    // token存放到请求头中
        (config.headers as any).common['Authorization'] = token;
    }

    // post请求参数在 config.data里,get请求在config.params里面
    let type: 'params' | 'data' = config.method == 'post' ? 'data' : 'params'

    // 可以在里面追参数,例如添加一个时间戳time
    // config[type] = {
    //     ...config[type],
    //     time: Date.now()
    // }

    return config;
}, (error) => {
    // 对请求错误做些什么
    return Promise.reject(error);
});

// 添加响应拦截器
service.interceptors.response.use((response) => {
    // 对响应数据做点什么

    // 例如登录失效的操作
    // const res = response.data;
    // if (res.code && res.code == 403) {
    //     // `token` 过期或者账号已在别处登录
    //     sessionStorage.clear(); // 清除浏览器全部临时缓存
    //     window.location.href = '/'; // 去登录页
    //     ElMessageBox.alert('账号已过期,请重新登录', '提示', {})
    //         .then(() => { })
    //         .catch(() => { });
    //     return Promise.reject(service.interceptors.response);
    // } else {
    //     return response.data;
    // }
    return response.data;      // 这里返回 response.data,默认返回整个axios对象,后端返回的在response.data包起来了
}, (error) => {
    // 对响应错误做点什么
    if (error.message.indexOf('timeout') != -1) {
        ElMessage.error('网络超时');
    } else if (error.message == 'Network Error') {
        ElMessage.error('网络连接错误');
    } else {
        ElMessage.error(error.response.status + ',' + error.response.statusText);
        //    if (error.response.data)  else ElMessage.error('接口路径找不到');
    }
    return Promise.reject(error);
});


/**
 * 跟后端约定返回的数据格式
 */
interface ResponseData<T> {
    code: number;   //  状态码,示例:-  200 : 成功
    msg: string;    // 返回文字描述,示例:-  提交成功
    data: T;    // 泛型数据,定义接口时传过来类型
}

/*** 方法封装 **********************************/
/**
 * @method post请求
 * @param {string} url 请求接口路由地址
 * @param {any} [data] 接口参数
 * @param {any} [config] 请求头部配置信息
 * @returns {Promise<ResponseData<T>>}
 */
const post = <T = any>(url: string, data?: any, config?: any): Promise<ResponseData<T>> => {
    return service.post(url, data, { ...config })
}

/**
 * @method get请求
 * @param {string} url 请求接口路由地址
 * @param {any} [data] 接口参数
 * @param {any} [config] 请求头部配置信息
 * @returns {Promise<ResponseData<T>>}
 */
const get = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ResponseData<T>> => {
    return service.get(url, {
        params: data,
        ...config
    })
}

/**
 * @method del删除
 * @param {string} url 请求接口路由地址
 * @param {any} [data] 接口参数
 * @param {any} [config] 请求头部配置信息
 * @returns {Promise<ResponseData<T>>}
 */
const del = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ResponseData<T>> => {
    return service.delete(url, {
        params: data,
        ...config
    })
}
/**
 * @method put请求
 * @param {string} url 请求接口路由地址
 * @param {any} [data] 接口参数
 * @param {any} [config] 请求头部配置信息
 * @returns {Promise<ResponseData<T>>}
 */
const put = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ResponseData<T>> => {
    return service.put(url, data, { ...config })
}

// 导出 axios 实例
export { post, get, del, put, service as request }
// export default service;

七、总结

  二次封装axios方法很多,文章也很多,关键是适合自己,符合项目需求才是最好的,有些东西还是需要根据业务需求来写的,不一定写的越多越好!

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐