05-vue3+ts中axios的封装
vue3+ts中axios的封装
安装 axios
npm install axios
一、axios 的类型解析
Axios 几个常用类型:
- AxiosInstance: axios 实例类型
- AxiosRequestConfig: axios 请求配置类型
- AxiosResponse: axios 响应类型
- AxiosError: axios 错误类型
1、AxiosRequestConfig
AxiosRequestConfig 是我们使用 axios 发送请求传递参数的类型。当然它也是我们请求拦截器里面的参数类型。
2、AxiosInstance
- AxiosInstance 是 axios 的实例类型。
- axios.create(config?: AxiosRequestConfig)创建出来的对象都是AxiosInstance类型!
3、AxiosResponse
- AxiosResponse 是 axios 响应类型。
- 我们可以在响应拦截器中获取到响应数据。
export interface AxiosResponse<T = any> {// 后端接口数据data: T;// http状态码status: number;// 来自服务器响应的 HTTP 状态信息statusText: string;// 响应头headers: any;// 请求配置信息config: AxiosRequestConfig;// 请求request?: any;
}
4、AxiosError
AxiosError 是 axios 错误类型。可以在请求或响应拦截器中获取到错误信息。
二、封装axios
本质:axios二次封装,就是使用请求和响应拦截器!
1、步骤
- 1.创建axios实例: axios.create(config配置对象)
- 2.axios添加请求拦截器:主要是操作config对象:
axios.interceptors.request.use((config)=>{return config})
- 3.响应拦截器
axios.interceptors.response.use((response)=>{return response})
2、实现代码
- 基于restful风格,提供了相对应的方法,方便调用!
- 在src目录下,创建api目录,创建request.ts,代码如下:
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig } from "axios";
import { base_url, TOKEN } from "@/config/com/base";
import toast from "@/config/utils/toast";
import { ElLoading } from "element-plus";
import useLoginStore from "@/store/login_store";
import cache from "@/config/utils/cache";
import router from "@/router";
/*** axios二次封装,就是使用请求和响应拦截器* --- 创建axios对象: axios.create(config配置对象)* --- 给axios添加请求拦截器:主要是操作config对象* axios.interceptors.request.use((config)=>{return config})* --- 给axios添加响应拦截器:* request.interceptors.response.use();* ---------------------------------------------------------* -- 定义一个Request类:两个属性* --- 属性:instance:AxiosInstance类型* axios的实例对象* --- 属性:baseConfig: AxiosRequestConfig类型* 基本的配置信息:baseURL,timeout* --- 属性:* ---------------------------------------------------------* */// 定义一个类Request!
class Request {//axios.create()返回axios对象instance: AxiosInstance;loadingInstance: any; // 用于存储ElLoading实例的变量//axios.create(config配置对象)需要的configbaseConfig: AxiosRequestConfig = { baseURL: base_url, timeout: 5000 };constructor(config: AxiosRequestConfig) {// 还得提供额外的config配置!所以使用了Object.assign()this.instance = axios.create(Object.assign(this.baseConfig, config));//在构造器初始化时候 添加 请求拦截器: 主要操作config对象this.instance.interceptors.request.use((config: any) => {// 创建ElLoading实例并显示加载提示,这里可以配置一些加载提示的相关属性,比如文本、背景遮罩等this.loadingInstance = ElLoading.service({text: "正在加载...",fullscreen: true,background: "rgba(0, 0, 0, 0.05)",});//添加token:const userStore = useLoginStore();let token = userStore.token;if (token) {config.headers["Authorization"] = `Bearer ${token}`;}return config;},(error) => {// 请求错误,这里可以用全局提示框进行提示return Promise.reject(error);});this.instance.interceptors.response.use( // 添加响应拦截器(res: any) => {// console.log('request.ts --- 响应拦截器:'+res);// 关闭ElLoading实例,隐藏加载提示if (this.loadingInstance) {this.loadingInstance.close();}return res.data;},// 失败响应(err: any) => {// 这里是AxiosError类型,所以一般我们只reject我们需要的响应即可// 关闭ElLoading实例,隐藏加载提示if (this.loadingInstance) {this.loadingInstance.close();}console.log("拦截器--error=" + JSON.stringify(err.response.data.data));let message = "";switch (err.response.status) {case 400:message = "code = 400 :" + JSON.stringify(err.response.data.data);break;case 401:console.log("401---token认证失败---");message = err.response.data.data?.detail;// 这里可以做清空storage并跳转到登录页的操作,处理只需要清空token即可,cache.removeCache(TOKEN);router.replace("/login");// 强制刷新window.location.reload();break;case 403:message = "权限不够,拒绝访问(403)";break;case 404:message = "请求地址无效(404)";break;case 405:message = "请求方法不被允许(405)";break;case 500:message = "服务器错误(500)";break;default:message = `连接出错(${err.response.status})!`;}// 错误消息可以使用全局弹框展示出来 :比如element plus 可以使用 ElMessage// `${message},请检查网络或联系管理员!`if (err.response.data.data) {// toast.error(message + " : " + JSON.stringify(err.response.data.data));toast.error(message);} else {toast.error(message + " : " + "服务器好像没有开启");}return Promise.reject(err.response);});}// 封装get请求!public get(url: string, params?: any): Promise<any> {return this.instance.get(url, { params });}public get_by_id(url: string, id: Number): Promise<any> {return this.instance.get(url + id + "/");}// 封装post请求!保存操作public post(url: string, data: any): Promise<any> {return this.instance.post(url, data);}// 封装put请求!public put(url: string, data: any): Promise<any> {return this.instance.put(url + data.id + "/", data);}// 根据id删除的方法(资源地址,资源id)public delete_by_id(url: string, id: Number): Promise<any> {return this.instance.delete(url + id + "/");}// 根据pic删除的方法:把参数封装到params配置项中public delete_pic(url: string, params?: any): Promise<any> {return this.instance.delete(url, { params });}// 把参数封装到data配置项中public delete_selected(url: string, data?: any): Promise<any> {return this.instance.delete(url, { data });}
}
// 默认导出Request实例!
export default new Request({});
封装中使用到的其它依赖文件:
- base.ts
import { base_url, TOKEN } from "@/config/com/base";
// 配置项目的基本信息的文件
//特别注意。图片路径最后要添加斜杠!不然图片显示失败
export const base_url: string = import.meta.env.VITE_APP_BASE_API;
export const TOKEN = "token";
- toast.ts : 是对Elment-plus的提示信息的封装(个人选择)
import toast from "@/config/utils/toast";
// 用于封装一些全局的hook,可以单独导入某些方法使用,也可以统一导入 hook 对象,从 hook 对象中 . 具体的方法
import { ElMessage, ElMessageBox, ElNotification } from "element-plus";
/*** 封装一个全局的 message 方法,用于显示消息提示* @param message 消息内容* @param type 消息类型,默认为 success*/
export const message = (message: string) => {ElMessage({message,type: "success",});
};
/*** 封装一个全局的 notification 方法,用于显示通知* @param message 通知内容* @param title 通知标题,默认为 '提示'*/
export const notify = (message: string) => {ElNotification({// title,message,type: "success",});
};
export const error = (message: string) => {ElNotification({message,type: "error",});
};
/*** 封装一个全局的 confirm 方法,用于显示确认对话框* @param message 对话框内容* @param title 对话框标题,默认为 '提示'* @param [options] 对话框选项* @return Promise<boolean>*/
export const confirm = (message: string, title = "提示", options: any = {}) => {if (Object.keys(options).length == 0) {options = {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",};}return new Promise((resolve, reject) => {ElMessageBox.confirm(message, title, options).then(() => {resolve(true);}).catch(() => {reject(false);});});
};
/*** 统一导出一个 hook 方法对象,包含所有 hook 方法*/
export default {message,confirm,notify,error,
};
/*** 使用该hooks方式如下:
import hooks from "@/config/utils/index";
hooks.message('操作成功') // 成功弹出
hooks.notification('恭喜你学会了使用全局通知组件', '操作成功', { type: 'success' }) // 成功弹出
hooks.confirm('确认要删除吗?').then((res) => console.log(res)) // 成功弹出*/
- login_store.ts : 仅给出示例代码
import useLoginStore from "@/store/login_store";
import { defineStore } from "pinia";
import { TOKEN } from "@/config/com/base";
import cache from "@/config/utils/cache";
import { ref } from "vue";
export const useLoginStore = defineStore("login", () => {const token = ref("");const login = () => {// 实现逻辑};return {token,login}
});
- cache.ts : 这是封装的localstorage使用的工具类!
import cache from "@/config/utils/cache";
/*** 封装localStorage的使用:* import cache from "@/config/utils/cache";* cache.xxx()即可!*/
class Cache {setCache(key: string, value: any) {if (value) {localStorage.setItem(key, JSON.stringify(value));}}getCache(key: string) {const value = localStorage.getItem(key);if (value) {return JSON.parse(value);}return "";}removeCache(key: string) {localStorage.removeItem(key);}clear() {localStorage.clear();}
}
export default new Cache();
3、发送请求的示例代码:
以下代码是使用request的格式示例:
- 发送请求即可复制格式,修改参数即可!
import request from "@/api/request";// 以下 用到的请求地址示例:
// api_sy.user = "/sy/user/", //操作用户的url
// 表单数据
let form = reactive({id:xxxx, //修改时候传递!username: "",password: "",name: "",phone: '',is_active: true,is_staff: true,avatar: "",
})
发送get请求:
// 发送get请求
request.get(api_sy.user, params).then(resp => {console.log(resp.data)
})
发送post请求:
// 发送post请求
request.post(api_sy.user, form).then(resp => {console.log(resp.data)
})
发送put请求:
// 发送put请求
request.put(api_sy.user, form).then(resp => {console.log(resp.data)
})
发送delete请求:
// 发送delete请求
request.delete_by_id(api_sy.user, id).then(resp => {console.log(resp.data)
})