搭建项目过程中有一个封装网络请求的步骤,现在已react+vite项目详细描述一下:
api文件夹,包含path文件夹:请求接口地址,index.ts:统一导出接口调用点,server.ts:api请求通用操作,tool.ts:处理server.ts的函数
sever.ts
import axios from "axios";
import {
handleRequestHeader,
handleAuth,
handleAuthError,
handleGeneralError,
handleNetworkError,
} from "./tools";
interface FcResponse<T> {
code: number;
message: string;
data: T;
}
interface IAnyObj {
[index: string]: unknown;
}
//封装get post put delete请求
//params一般是拼接的参数
//data一般是json格式的数据
//config是自定义的参数,里面携带的是 AbortController控制器的signal属性
//get请求方式
export const Get = <T>(
url: string,
params: IAnyObj = {},
config?: any,
): Promise<[any, FcResponse<T> | undefined]> =>
new Promise((resolve) => {
axios
.get(url, { params, ...config })
.then((result) => {
resolve([null, result.data as FcResponse<T>]);
})
.catch((err) => {
resolve([err, undefined]);
});
});
//post请求
export const Post = <T>(
url: string,
data: IAnyObj = {},
params: IAnyObj = {},
): Promise<[any, FcResponse<T> | undefined]> => {
return new Promise((resolve) => {
axios
.post(url, data, { params })
.then((result) => {
resolve([null, result.data as FcResponse<T>]);
})
.catch((err) => {
resolve([err, undefined]);
});
});
};
//put请求
export const Put = <T>(
url: string,
data: IAnyObj = {},
params: IAnyObj = {},
): Promise<[any, FcResponse<T> | undefined]> => {
return new Promise((resolve) => {
axios
.put(url, data, { params })
.then((result) => {
resolve([null, result.data as FcResponse<T>]);
})
.catch((err) => {
resolve([err, undefined]);
});
});
};
//Delete请求
export const Delete = <T>(
url: string,
params: IAnyObj = {},
data: IAnyObj = {},
config?: any,
): Promise<[any, FcResponse<T> | undefined]> => {
return new Promise((resolve) => {
axios
.delete(url, { params, data, ...config })
.then((result) => {
resolve([null, result.data as FcResponse<T>]);
})
.catch((err) => {
resolve([err, undefined]);
});
});
};
//拦截器
// 请求拦截
let signal:any= null;//存储传递过来的控制器signal属性
axios.interceptors.request.use((config) => {
//控制器signal赋值
if (config.signal) {
signal = config.signal;
} else {
signal = null;
}
//配置header和token(方法在tool.ts文件中)
config = handleRequestHeader(config);
config = handleAuth(config);
return config;
});
//响应拦截
axios.interceptors.response.use(
//响应/请求成功
(response) => {
//响应成功了但是状态不是200的其他2xx成功的状态码,返回promise控制台报红错误
if (response.status !== 200) return Promise.reject(response.data);
//200状态码根据data的code判断登陆是否失效
//如果登陆失效,不进行下一个方法验证
//如果不是,进行下一个方法验证
handleAuthError(response.data.code) && handleGeneralError(response.data.code, response.data.message);
return response;
},
//响应/请求失败
(err) => {
//取消请求会报错
//有sigal属性并且sigal属性的aborted为true的时候是中断请求的错误
//其他情况则是正常响应报错
if (!(signal && signal.aborted)) {
//处理响应错误的方法
handleNetworkError(err?.response?.status);
//返回promise控制台报红错误
Promise.reject(err.response);
}
},
)
tool.ts
//处理api业务函数
import { message } from "antd";
import { Local, Session } from "@/utils/storage";
//请求拦截
//请求拦截处理header
export const handleRequestHeader = (config: any) => {
config["baseURL"] = import.meta.env.VITE_API_URL as any;
config["timeout"] = "20000";
return config;
};
//请求拦截设置token
export const handleAuth = (config: any) => {
if (Local.get("token")) {
config.headers["token"] = Local.get("token") || "";
}
return config;
};
//响应拦截
//响应成功拦截登陆失效
export const handleAuthError = (errno: any) => {
const authErrMap: any = {
5000: "登录失效,需要重新登录", // token 失效
};
if (Object.prototype.hasOwnProperty.call(authErrMap, errno)) {
//清空本地的信息
Session.clear();
Local.clear();
//页面重新加载,经过权限组建的时候会跳转到登陆页面
window.location.reload();
return false;
}
return true;
};
//请求成功如果返回的不是登陆失效
export const handleGeneralError = (errno: any, errmsg: any) => {
if (errno && errno !== 200) {
message.error(errmsg ?? "未知错误");
return false;
}
return true;
};
//响应失败,根据状态码进行错误提示
export const handleNetworkError = (errStatus: number) => {
let errMessage = "未知错误";
const errMsgMap: any = {
400: "错误的请求",
401: "未授权,请重新登录",
403: "拒绝访问",
404: "请求错误,未找到该资源",
405: "请求方法未允许",
408: "请求超时",
500: "服务器端出错",
501: "网络未实现",
502: "网络错误",
503: "服务不可用",
504: "网络超时",
505: "http版本不支持该请求",
};
if (errStatus) {
errMessage = errMsgMap[errStatus] || `其他连接错误 --${errStatus}`;
} else {
errMessage = `无法连接到服务器!`;
}
message.error(errMessage);
};
取消请求的代码
api->demind.ts
// 历史记录
export const getDemandHistory = <T = []>(data: any): ApiResponse<T> => {
return Get<T>(`/flow/${data.procInsId}/record/lst`, {}, { signal: data.signal });
};
export const demandApi = {
getDemandHistory
}
组件xx.tsx
...
// 获取各流程审批记录
const getFlowAPI = async (procInsId: string) => {
//创建AbortController对象
controller = new AbortController();
//请求的时候传入AbortController对象的signal属性
const [err, res] = await api.getDemandHistory({ procInsId, signal: controller.signal });
if (!err && res?.data) {
return res.data;
} else {
return [];
}
};
//tab切换的时候取消
const tabChange = (procInsId: string) => {
//取消请求
controller && controller.abort();
setTabActive(procInsId);
setTimeout(() => {
getFlowAH(procInsId, getCodeById(procInsId));
}, 100);
};
...