UNIVPLMDataIntegration/Web/src/utils/axios-utils.ts
zuohuaijun 5074b67f65 😎初始化
2024-06-15 13:02:35 +08:00

245 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 当前版本v1.4.0
* 使用描述https://editor.swagger.io 代码生成 typescript-axios 辅组工具库
* 依赖说明:适配 axios 版本v0.21.4
* 视频教程https://www.bilibili.com/video/BV1EW4y1C71D
*/
import globalAxios, { AxiosInstance } from 'axios';
import { Configuration } from '../api-services';
import { BaseAPI, BASE_PATH } from '../api-services/base';
import { ElMessage } from 'element-plus';
import { Local, Session } from '../utils/storage';
// 接口服务器配置
export const serveConfig = new Configuration({
basePath: window.__env__.VITE_API_URL,
});
// token 键定义
export const accessTokenKey = 'access-token';
export const refreshAccessTokenKey = `x-${accessTokenKey}`;
// 获取 token
export const getToken = () => {
return Local.get(accessTokenKey);
};
// 获取请求头 token
export const getHeader = () => {
return { authorization: 'Bearer ' + getToken() };
};
// 清除 token
export const clearAccessTokens = () => {
clearTokens();
// 刷新浏览器
window.location.reload();
};
// 清除 token
export const clearTokens = () => {
Local.remove(accessTokenKey);
Local.remove(refreshAccessTokenKey);
Session.clear();
};
// axios 默认实例
export const axiosInstance: AxiosInstance = globalAxios;
// 这里可以配置 axios 更多选项 =========================================
axiosInstance.defaults.timeout = 1000 * 60 * 10; // 设置超时,默认 10 分钟
// axios 请求拦截
axiosInstance.interceptors.request.use(
(conf) => {
// 获取本地的 token或session中的token
const accessToken = Local.get(accessTokenKey) ? Local.get(accessTokenKey) : Session.get('token');
if (accessToken) {
// 将 token 添加到请求报文头中
conf.headers!['Authorization'] = `Bearer ${accessToken}`;
// 判断 accessToken 是否过期
const jwt: any = decryptJWT(accessToken);
const exp = getJWTDate(jwt.exp as number);
// token 已经过期
if (new Date() >= exp) {
// 获取刷新 token
const refreshAccessToken = Local.get(refreshAccessTokenKey);
// 携带刷新 token
if (refreshAccessToken) {
conf.headers!['X-Authorization'] = `Bearer ${refreshAccessToken}`;
}
}
}
// 这里编写请求拦截代码 =========================================
// 获取前端设置的语言
const globalI18n = Local.get('themeConfig')?.globalI18n;
if (globalI18n) {
// 添加到请求报文头中
conf.headers!['Accept-Language'] = globalI18n;
}
return conf;
},
(error) => {
// 处理请求错误
if (error.request) {
ElMessage.error(error);
}
// 请求错误代码及自定义处理
ElMessage.error(error);
return Promise.reject(error);
}
);
// axios 响应拦截
axiosInstance.interceptors.response.use(
(res) => {
// 获取状态码和返回数据
var status = res.status;
var serve = res.data;
// 处理 401
if (status === 401) {
clearAccessTokens();
}
// 处理未进行规范化处理的
if (status >= 400) {
throw new Error(res.statusText || 'Request Error.');
}
// 处理规范化结果错误
if (serve && serve.hasOwnProperty('errors') && serve.errors) {
throw new Error(JSON.stringify(serve.errors || 'Request Error.'));
}
// 读取响应报文头 token 信息
var accessToken = res.headers[accessTokenKey];
var refreshAccessToken = res.headers[refreshAccessTokenKey];
// 判断是否是无效 token
if (accessToken === 'invalid_token') {
clearAccessTokens();
}
// 判断是否存在刷新 token如果存在则存储在本地
else if (refreshAccessToken && accessToken && accessToken !== 'invalid_token') {
Local.set(accessTokenKey, accessToken);
Local.set(refreshAccessTokenKey, refreshAccessToken);
}
// 响应拦截及自定义处理
if (serve.code === 401) {
clearAccessTokens();
} else if (serve.code === undefined) {
return Promise.resolve(res);
} else if (serve.code !== 200) {
var message;
// 判断 serve.message 是否为对象
if (serve.message && typeof serve.message == 'object') {
message = JSON.stringify(serve.message);
} else {
message = serve.message;
}
// 用户自定义处理异常
if (!res.config?.customCatch) {
ElMessage.error(message);
}
throw new Error(message);
}
return res;
},
(error) => {
// 处理响应错误
if (error.response) {
if (error.response.status === 401) {
clearAccessTokens();
}
}
// 用户自定义处理异常
if (!error.config?.customCatch) {
// 响应错误代码及自定义处理
ElMessage.error(error);
}
return Promise.reject(error);
}
);
/**
* 包装 Promise 并返回 [Error, any]
* @param promise Promise 方法
* @param errorExt 自定义错误信息(拓展)
* @returns [Error, any]
*/
export function feature<T, U = Error>(promise: Promise<T>, errorExt?: object): Promise<[U, undefined] | [null, T]> {
return promise
.then<[null, T]>((data: T) => [null, data])
.catch<[U, undefined]>((err: U) => {
if (errorExt) {
const parsedError = Object.assign({}, err, errorExt);
return [parsedError, undefined];
}
return [err, undefined];
});
}
/**
* 获取/创建服务 API 实例
* @param apiType BaseAPI 派生类型
* @param configuration 服务器配置对象
* @param basePath 服务器地址
* @param axiosObject axios 实例
* @returns 服务API 实例
*/
export function getAPI<T>(
// eslint-disable-next-line no-unused-vars
apiType: new (configuration?: Configuration, basePath?: string, axiosInstance?: AxiosInstance) => T,
configuration: Configuration = serveConfig,
basePath: string = BASE_PATH,
axiosObject: AxiosInstance = axiosInstance
) {
return new apiType(configuration, basePath, axiosObject);
}
/**
* 解密 JWT token 的信息
* @param token jwt token 字符串
* @returns <any>object
*/
export function decryptJWT(token: string): any {
token = token.replace(/_/g, '/').replace(/-/g, '+');
var json = decodeURIComponent(escape(window.atob(token.split('.')[1])));
return JSON.parse(json);
}
/**
* 将 JWT 时间戳转换成 Date
* @description 主要针对 `exp``iat``nbf`
* @param timestamp 时间戳
* @returns Date 对象
*/
export function getJWTDate(timestamp: number): Date {
return new Date(timestamp * 1000);
}
/**
* 实现异步延迟
* @param delay 延迟时间(毫秒)
* @returns
*/
export function sleep(delay: number) {
return new Promise((resolve) => setTimeout(resolve, delay));
}