2024-10-13 19:49:48 +08:00
|
|
|
|
import type { RequestOptions } from '@@/plugin-request/request';
|
|
|
|
|
|
import { RequestConfig, request } from '@umijs/max';
|
|
|
|
|
|
import { message } from 'antd';
|
|
|
|
|
|
import { history } from 'umi';
|
|
|
|
|
|
|
|
|
|
|
|
// 错误处理方案: 错误类型
|
|
|
|
|
|
enum ErrorShowType {
|
|
|
|
|
|
SILENT = 0,
|
|
|
|
|
|
WARN_MESSAGE = 1,
|
|
|
|
|
|
ERROR_MESSAGE = 2,
|
|
|
|
|
|
NOTIFICATION = 3,
|
|
|
|
|
|
REDIRECT = 9,
|
|
|
|
|
|
}
|
|
|
|
|
|
// 与后端约定的响应数据格式
|
|
|
|
|
|
interface ResponseStructure {
|
|
|
|
|
|
code: number;
|
|
|
|
|
|
data: any;
|
|
|
|
|
|
message?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加一个刷新 token 的函数
|
|
|
|
|
|
const refreshToken = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let refreshTokenId = localStorage.getItem('refreshToken');
|
|
|
|
|
|
if (!refreshTokenId) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
let userId = JSON.parse(localStorage.getItem('userInfo') ?? "{}").id;
|
|
|
|
|
|
// 这里实现刷新 token 的逻辑
|
|
|
|
|
|
const response = await request('/lms/User/RefreshToken', {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
"Content-Type": "application/json"
|
|
|
|
|
|
},
|
|
|
|
|
|
data: {
|
|
|
|
|
|
refreshToken: refreshTokenId,
|
|
|
|
|
|
"userId": userId,
|
|
|
|
|
|
"deviceInfo": "2"
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
2024-10-18 12:46:58 +08:00
|
|
|
|
|
2024-10-13 19:49:48 +08:00
|
|
|
|
if (response.code == 1) {
|
|
|
|
|
|
localStorage.setItem('token', response.data);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('刷新 token 失败', error);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const retryRequest = async (url: string, opts: RequestOptions) => {
|
|
|
|
|
|
if (url) {
|
|
|
|
|
|
try {
|
2024-10-18 12:46:58 +08:00
|
|
|
|
|
2024-10-13 19:49:48 +08:00
|
|
|
|
const response = await request(url, {
|
|
|
|
|
|
...opts,
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
...opts.headers,
|
|
|
|
|
|
'Authorization': `Bearer ${localStorage.getItem('token')}`,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
return response;
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('重试请求失败', error);
|
|
|
|
|
|
throw error;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
throw new Error('url is required for retryRequest');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @name 错误处理
|
|
|
|
|
|
* pro 自带的错误处理, 可以在这里做自己的改动
|
|
|
|
|
|
* @doc https://umijs.org/docs/max/request#配置
|
|
|
|
|
|
*/
|
|
|
|
|
|
export const errorConfig: RequestConfig = {
|
|
|
|
|
|
// 错误处理: umi@3 的错误处理方案。
|
|
|
|
|
|
errorConfig: {
|
|
|
|
|
|
// 错误抛出
|
|
|
|
|
|
errorThrower: (res) => {
|
|
|
|
|
|
const { code, data, message } =
|
|
|
|
|
|
res as unknown as ResponseStructure;
|
|
|
|
|
|
if (code != 1) {
|
|
|
|
|
|
const error: any = new Error(message);
|
|
|
|
|
|
error.name = 'BizError';
|
|
|
|
|
|
error.info = { message };
|
|
|
|
|
|
throw error; // 抛出自制的错误
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 错误接收及处理
|
|
|
|
|
|
errorHandler: async (error: any, opts: any) => {
|
|
|
|
|
|
let url = error.config.url;
|
|
|
|
|
|
if (opts?.skipErrorHandler) throw error;
|
|
|
|
|
|
// 我们的 errorThrower 抛出的错误。
|
|
|
|
|
|
if (error.name === 'BizError') {
|
2024-10-18 12:46:58 +08:00
|
|
|
|
|
2024-10-13 19:49:48 +08:00
|
|
|
|
} else if (error.response) {
|
|
|
|
|
|
// 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
|
|
|
|
|
|
const { status } = error.response;
|
|
|
|
|
|
if (status === 401) {
|
|
|
|
|
|
if (url.toLowerCase().includes('/refreshtoken')) {
|
|
|
|
|
|
message.error('登录已过期,请重新登录');
|
|
|
|
|
|
localStorage.removeItem('token');
|
|
|
|
|
|
localStorage.removeItem('refreshToken');
|
|
|
|
|
|
localStorage.removeItem('userInfo');
|
|
|
|
|
|
history.push('/user/login');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 尝试刷新 token
|
|
|
|
|
|
const refreshSuccess = await refreshToken();
|
|
|
|
|
|
if (refreshSuccess) {
|
|
|
|
|
|
// 刷新成功,重试原请求
|
|
|
|
|
|
// 这里需要实现重试逻辑,可能需要修改您的请求库
|
|
|
|
|
|
message.success('已重新获取授权,正在重试请求');
|
|
|
|
|
|
// 刷新成功,重试原请求
|
|
|
|
|
|
try {
|
|
|
|
|
|
const retryResponse = await retryRequest(url, opts);
|
|
|
|
|
|
// 如果重试成功,返回重试的响应
|
|
|
|
|
|
return retryResponse;
|
|
|
|
|
|
} catch (retryError) {
|
|
|
|
|
|
message.error('重试请求失败,请重新登录');
|
|
|
|
|
|
localStorage.removeItem('token');
|
|
|
|
|
|
localStorage.removeItem('refreshToken');
|
|
|
|
|
|
localStorage.removeItem('userInfo');
|
|
|
|
|
|
history.push('/user/login');
|
|
|
|
|
|
}
|
|
|
|
|
|
// 重试原请求的逻辑
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 刷新失败,重定向到登录页面
|
|
|
|
|
|
message.error('授权已过期,请重新登录');
|
|
|
|
|
|
localStorage.removeItem('token');
|
|
|
|
|
|
localStorage.removeItem('refreshToken');
|
|
|
|
|
|
localStorage.removeItem('userInfo');
|
|
|
|
|
|
history.push('/user/login');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 这边要判断是不是刷新token的时候401,如果是刷新token的时候401,就不跳转到登录页面
|
|
|
|
|
|
// message.error('未授权,请重新登录');
|
|
|
|
|
|
// history.push('/user/login'); // 重定向到登录页面
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (error.request) {
|
2024-10-18 12:46:58 +08:00
|
|
|
|
|
2024-10-13 19:49:48 +08:00
|
|
|
|
// 请求已经成功发起,但没有收到响应
|
|
|
|
|
|
// \`error.request\` 在浏览器中是 XMLHttpRequest 的实例,
|
|
|
|
|
|
// 而在node.js中是 http.ClientRequest 的实例
|
|
|
|
|
|
message.error('None response! Please retry.');
|
|
|
|
|
|
} else {
|
2024-10-18 12:46:58 +08:00
|
|
|
|
|
2024-10-13 19:49:48 +08:00
|
|
|
|
// 发送请求时出了点问题
|
|
|
|
|
|
message.error('Request error, please retry.');
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 请求拦截器
|
|
|
|
|
|
requestInterceptors: [
|
|
|
|
|
|
(config: RequestOptions) => {
|
|
|
|
|
|
// 拦截请求配置,进行个性化处理。
|
|
|
|
|
|
// 添加校验头
|
|
|
|
|
|
// config.baseURL = 'https://localhost:44362';
|
2024-10-18 12:46:58 +08:00
|
|
|
|
config.baseURL = window.location.origin.includes('localhost') ? 'https://localhost:44362' : window.location.origin;
|
2024-10-13 19:49:48 +08:00
|
|
|
|
const headers = {
|
|
|
|
|
|
...config.headers, // 保留已有的请求头
|
|
|
|
|
|
'Authorization': `Bearer ${localStorage.getItem('token')}`, // 添加新的请求头
|
|
|
|
|
|
// 你可以根据需要添加更多的请求头
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return { ...config, headers };
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
|
|
// 响应拦截器
|
|
|
|
|
|
responseInterceptors: [
|
|
|
|
|
|
(response) => {
|
|
|
|
|
|
// 拦截响应数据,进行个性化处理
|
|
|
|
|
|
const { data } = response as unknown as ResponseStructure;
|
|
|
|
|
|
|
|
|
|
|
|
if (data?.success === false) {
|
|
|
|
|
|
message.error('请求失败!');
|
|
|
|
|
|
}
|
|
|
|
|
|
return response;
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
};
|