github仓库地址: github.com/Liangjiahon...
- 安装
axios
shell
pnpm i axios
- 在根目录下新建
service
文件夹,进行axios
封装
目录结构如下

- modules: 区分每个模块下的请求,如登录退出的房
auth.js
中,首页相关请求放home.js
中 - index: 用于同一暴露各个模块的请求
- request: 二次封装的请求类
实现一个
Request
类,对axios
的二次封装
- 初始化请求相关的信息
javascript
// request.js
import axios from "axios";
class Request {
constructor(baseURL, timeout) {
this.instance = axios.create({
baseURL,
timeout,
// 添加默认的Content-Type
headers: { "Content-Type": "application/x-www-form-urlencoded" }
});
this.showLoading = false; // 用于控制loading
this.loadingInstance = null; // loading实例
this.interceptorsSetup(); // 建立请求拦截和响应拦截
}
}
const { VITE_BASE_URL } = import.meta.env;
const request = new Request(VITE_BASE_URL, 2000);
export default request;
- 实现请求和响应拦截
javascript
import router from "@/router";
import useLoading from "@/hooks/useLoading";
class Request {
...
interceptorsSetup() {
this.instance.interceptors.request.use(
(config) => {
// 判断请求时有没有传入loading
this.showLoading = config.showLoading ?? this.showLoading;
// 有传入loading就显示
if (this.showLoading) {
const { loadingInstance } = useLoading();
this.loadingInstance = loadingInstance;
}
// 有token则带上到请求头中
const token = localStorage.getItem("token") || "";
if (token) {
config.headers && (config.headers["token"] = token);
}
return config;
},
(err) => {
console.error("网络请求出错", err);
this.loadingInstance?.close();
return err;
}
);
this.instance.interceptors.response.use(
(response) => {
// 请求完成,关闭loading
this.loadingInstance?.close();
const { code } = response.data;
// 判断token是否过期,过期则跳转到登录页面并清除token
if (code === 401) {
localStorage.removeItem("token");
router.replace("/login");
return Promise.reject(response.data);
}
return response;
},
(err) => {
console.log("请求响应报错", err);
this.loadingInstance?.close();
return err;
}
);
}
}
- 结合
elementPlus
实现一个loading hook
- 在根目录下新建
hooks
目录,用于存放自定义的hooks
javascript
// hooks/useLoading.js
import { ElLoading } from "element-plus";
const useLoadingHook = (text = "loading") => {
const loadingInstance = ElLoading.service({
text,
background: "rgba(0, 0, 0, 0.7)"
});
const closeLoading = () => loadingInstance.close();
return { loadingInstance, closeLoading };
};
export default useLoadingHook;
- 实现基础请求方法,通过
Promise
返回请求结果
javascript
request(config) {
return new Promise((resolve, reject) => {
this.instance
.request(config)
.then((res) => {
resolve(res.data);
})
.catch((err) => {
console.log("request err:", err);
reject(err);
});
});
}
- 封装
get
、post
请求
javascript
get(config) {
return this.request({ ...config, method: "get" });
}
// 以params格式传参使用
post(config) {
return this.request({ ...config, method: "post" });
}
// 以Json格式传参使用
postJson(config) {
return this.request({
...config,
method: "post",
headers: { "Content-Type": "application/json" }
});
}
- 将封装的
request
实例暴露
javascript
const { VITE_BASE_URL } = import.meta.env; // 根据环境加载不同的请求地址
const request = new Request(VITE_BASE_URL, 2000);
export default request;
基于封装的
request
实例,实现登录接口函数
- 按照对应接口,将请求的函数写入到对应的模块中
javascript
// service/modules/auth.js
import request from "../request";
export const login = (params = {}) => {
return request.post({ url: "/login", params, showLoading: true });
};
- 通过
index
统一暴露
javascript
export * from "./modules/home";
export * from "./modules/auth";
使用定义好的请求函数
javascript
import { login } from "@/service";
login().then((res) => {
console.log(res);
});
