vue3+ts中axios的封装
安装 axios
bash
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 响应类型。
- 我们可以在响应拦截器中获取到响应数据。
ts
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对象:
js
axios.interceptors.request.use((config)=>{return config})
- 3.响应拦截器
js
axios.interceptors.response.use((response)=>{return response})
2、实现代码
- 基于restful风格,提供了相对应的方法,方便调用!
- 在src目录下,创建api目录,创建request.ts,代码如下:
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配置对象)需要的config
baseConfig: 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
csharp
import { base_url, TOKEN } from "@/config/com/base";
ts
// 配置项目的基本信息的文件
//特别注意。图片路径最后要添加斜杠!不然图片显示失败
export const base_url: string = import.meta.env.VITE_APP_BASE_API;
export const TOKEN = "token";
- toast.ts : 是对Elment-plus的提示信息的封装(个人选择)
ts
import toast from "@/config/utils/toast";
ts
// 用于封装一些全局的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 : 仅给出示例代码
csharp
import useLoginStore from "@/store/login_store";
csharp
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使用的工具类!
csharp
import cache from "@/config/utils/cache";
ts
/**
* 封装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的格式示例:
- 发送请求即可复制格式,修改参数即可!
ts
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请求:
ts
// 发送get请求
request.get(api_sy.user, params).then(resp => {
console.log(resp.data)
})
发送post请求:
ts
// 发送post请求
request.post(api_sy.user, form).then(resp => {
console.log(resp.data)
})
发送put请求:
ts
// 发送put请求
request.put(api_sy.user, form).then(resp => {
console.log(resp.data)
})
发送delete请求:
ts
// 发送delete请求
request.delete_by_id(api_sy.user, id).then(resp => {
console.log(resp.data)
})