ToB企服应用市场:ToB评测及商务社交产业平台
标题:
Axios 之 ts 版本的哀求封装
[打印本页]
作者:
农妇山泉一亩田
时间:
2024-6-20 19:24
标题:
Axios 之 ts 版本的哀求封装
1、安装
npm install axios
复制代码
文档链接:中文文档
2、常用封装
2.1 简单版本的封装
这里仅封装常用的 get、post、put、delete 几种方法
且只封装几种常见的报错提示
src/utils/request.ts
import axios, {
AxiosError,
AxiosInstance,
AxiosResponse,
InternalAxiosRequestConfig,
} from "axios";
const config = {
baseURL: "http://localhost:3000/api",
timeout: 10000,
withCredentials: true,
headers: {},
};
class RequestHttp {
service: AxiosInstance;
constructor() {
this.service = axios.create(config);
/**
* @description 请求拦截器
*/
this.service.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
return config;
}
);
/**
* @description 响应拦截器
*/
this.service.interceptors.response.use(
(response: AxiosResponse) => {
const { data } = response;
return data;
},
(error: AxiosError) => {
const { response } = error;
if (response) {
checkStatus(response.status);
}
return false;
}
);
}
// 常用请求方法封装
get(url: string, params?: object, _object = {}) {
return this.service.get(url, { params, ..._object });
}
post(url: string, params?: object, _object = {}) {
return this.service.post(url, params, _object);
}
put(url: string, params?: object, _object = {}) {
return this.service.put(url, params, _object);
}
delete(url: string, params?: any, _object = {}) {
return this.service.delete(url, { params, ..._object });
}
}
/**
* @description: 校验网络请求状态码
* @param {Number} status
* @return void
*/
const checkStatus = (status: number): void => {
switch (status) {
case 404:
console.warn("资源不存在!");
break;
case 405:
console.warn("请求方式错误!");
break;
case 500:
console.warn("服务器异常!");
break;
default:
console.warn("请求失败!");
}
};
const request = new RequestHttp();
export default request;
复制代码
2.1 包罗多处置惩罚的封装
增加如下处置惩罚
哀求loading
取消哀求(CancelToken)
哀求效果的更细节处置惩罚
src/utils/request.ts
import { message } from "antd";
import axios, {
AxiosInstance,
InternalAxiosRequestConfig,
AxiosResponse,
AxiosError,
} from "axios";
import { store } from "@/redux";
import { ResponseCodeEnum } from "@/enums/httpEnum";
import { setToken } from "@/redux/modules/global";
import { ResultData } from "@/api/types/index.type";
import fullLoading from "./fullLoading";
import { AxiosCancel } from "./AxiosCancel";
const config = {
baseURL: "http://localhost:3000/api",
timeout: 5000,
withCredentials: true,
headers: {},
};
const axiosCancel = new AxiosCancel();
class RequestHttp {
service: AxiosInstance;
constructor() {
this.service = axios.create(config);
/**
* @description 请求拦截器
*/
this.service.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
console.log(config)
// 打开全局 loading
// 如不需要全局 loading,则第三个参数 { headers: { noLoading: true } }
if(!config.headers.noLoading) {
fullLoading.show();
}
// 将请求添加到 pending 中
axiosCancel.addPending(config);
// 这里如果需要添加token
const token = store.getState().global.token; // 我这里用的是 react-redux + redux-toolkit
config.headers["X-Access-Token"] = token;
return config;
}
);
/**
* @description 响应拦截器
*/
this.service.interceptors.response.use(
(response: AxiosResponse) => {
const { data, config } = response;
// 关闭全局 loading
if(!config.headers.noLoading) {
fullLoading.hide();
}
// 请求结束,移除本次请求
axiosCancel.removePending(config.url, config.method);
// 接口返回 code 不是 200 的处理
if (data.code !== ResponseCodeEnum.SUCCESS) {
message.error(data.msg);
// 登录失效,清除 token,跳转到登录页面
if (data.code === ResponseCodeEnum.NOLOGIN) {
store.dispatch(setToken(""));
window.location.href = "/login";
}
return Promise.reject(data);
}
return data;
},
(error: AxiosError) => {
fullLoading.hide();
const { response } = error;
if (response) {
checkStatus(response.status);
}
return false;
}
);
}
// 常用请求方法封装
get<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
return this.service.get(url, { params, ..._object });
}
post<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
return this.service.post(url, params, _object);
}
put<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
return this.service.put(url, params, _object);
}
delete<T>(url: string, params?: any, _object = {}): Promise<ResultData<T>> {
return this.service.delete(url, { params, ..._object });
}
}
/**
* @description: 校验网络请求状态码
* @param {Number} status
* @return void
*/
const checkStatus = (status: number): void => {
switch (status) {
case 404:
message.error("资源不存在!");
break;
case 405:
message.error("请求方式错误!");
break;
case 500:
message.error("服务器异常!");
break;
default:
message.error("请求失败!");
}
};
const request = new RequestHttp();
export default request;
复制代码
取消哀求的封装:
src/utils/AxiosCancel.ts
import axios, { AxiosRequestConfig, Canceler } from "axios";
const cancelMap = new Map<string, Canceler>();
export class AxiosCancel {
/**
* 添加请求的 cancel
* @param config
*/
addPending(config: AxiosRequestConfig) {
const { url, method } = config;
if (!url || !method) return;
// 处理同个api,同时多次请求的情况,先移除上一个
this.removePending(url, method);
const key = getCancelMapKey(url, method);
config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
if (!cancelMap.has(key)) {
cancelMap.set(key, cancel);
}
});
}
/**
* 移除请求
* @param url
* @param method
*/
removePending(url: string | undefined, method: string | undefined) {
if (!url || !method) return;
const key = getCancelMapKey(url, method);
const cancel = cancelMap.get(key);
if (cancel) {
cancel();
cancelMap.delete(key);
}
}
/**
* 移除所有请求
*/
removeAllPending() {
cancelMap.forEach((cancel) => {
cancel && cancel();
});
cancelMap.clear();
}
}
function getCancelMapKey(url: string, method: string) {
return `${url}_${method}`;
}
复制代码
全局加载loading
src/utils/fullLoading.ts
import ReactDOM from "react-dom/client";
import { Spin } from "antd";
// 当前请求的个数
let reqCount = 0;
// 显示 loading
function show() {
if (reqCount === 0) {
const dom = document.createElement("div");
dom.id = "loading";
dom.style.position = "fixed";
dom.style.top = "0";
dom.style.right = "0";
dom.style.bottom = "0";
dom.style.left = "0";
dom.style.background = "rgba(0, 0, 0, 0.5)";
dom.style.display = "flex";
dom.style.justifyContent = "center";
dom.style.alignItems = "center";
dom.style.zIndex = "9999";
document.body.appendChild(dom);
ReactDOM.createRoot(dom).render(<Spin size="large"></Spin>);
}
reqCount++;
}
// 隐藏 loading
function hide() {
reqCount--;
if (reqCount === 0) {
const dom = document.getElementById("loading");
if (dom) {
document.body.removeChild(dom as HTMLElement);
}
}
}
const fullLoading = {
show,
hide,
};
export default fullLoading;
复制代码
src/enums/httpEnum.ts
/**
* @description:响应结果枚举
*/
export enum ResponseCodeEnum {
SUCCESS = 200,
ERROR = 500,
NOLOGIN = 499,
}
复制代码
类型文件
src/api/type/api.type.ts
// 接口返回结构,不包含 data
export interface ResponseResult {
// 状态码
code: number;
// 消息
msg: string;
}
// 完整的接口返回结构
export interface ResultData<T = any> extends ResponseResult {
// 数据
data: T;
}
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4