|
@@ -21,39 +21,36 @@ import errorCode from "./errorCode";
|
|
|
import { resetRouter } from "@/router";
|
|
import { resetRouter } from "@/router";
|
|
|
import { deleteUserCache } from "@hooks/useCache";
|
|
import { deleteUserCache } from "@hooks/useCache";
|
|
|
const { result_code, base_url, request_timeout } = config;
|
|
const { result_code, base_url, request_timeout } = config;
|
|
|
-// 需要忽略的提示。忽略后,自动 Promise.reject('error')
|
|
|
|
|
-const ignoreMsgs = [
|
|
|
|
|
- "无效的刷新令牌", // 刷新令牌被删除时,不用提示
|
|
|
|
|
- "刷新令牌已过期", // 使用刷新令牌,刷新获取新的访问令牌时,结果因为过期失败,此时需要忽略。否则,会导致继续 401,无法跳转到登出界面
|
|
|
|
|
-];
|
|
|
|
|
|
|
+// 需要忽略的提示。忽略后,自�?Promise.reject('error')
|
|
|
|
|
+const ignoreMsgs = ["无效的刷新令牌", "刷新令牌被删除", "刷新令牌已过期"];
|
|
|
// 是否显示重新登录
|
|
// 是否显示重新登录
|
|
|
export const isRelogin = { show: false };
|
|
export const isRelogin = { show: false };
|
|
|
export const reloginCancelKey = "reloginCancel";
|
|
export const reloginCancelKey = "reloginCancel";
|
|
|
export const manualLogoutKey = "manualLogout";
|
|
export const manualLogoutKey = "manualLogout";
|
|
|
-// Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
|
|
|
|
|
|
|
+// Axios 无感知刷新令牌,参考https://www.dashingdog.cn/article/11?https://segmentfault.com/a/1190000020210980 实现
|
|
|
// 请求队列
|
|
// 请求队列
|
|
|
let requestList: any[] = [];
|
|
let requestList: any[] = [];
|
|
|
-// 是否正在刷新中
|
|
|
|
|
|
|
+// 是否正在刷新?
|
|
|
let isRefreshToken = false;
|
|
let isRefreshToken = false;
|
|
|
// 请求白名单,无须token的接口
|
|
// 请求白名单,无须token的接口
|
|
|
const whiteList: string[] = ["/login", "/refresh-token"];
|
|
const whiteList: string[] = ["/login", "/refresh-token"];
|
|
|
|
|
|
|
|
// 创建axios实例
|
|
// 创建axios实例
|
|
|
const service: AxiosInstance = axios.create({
|
|
const service: AxiosInstance = axios.create({
|
|
|
- baseURL: base_url, // api 的 base_url
|
|
|
|
|
|
|
+ baseURL: base_url, // api �?base_url
|
|
|
timeout: request_timeout, // 请求超时时间
|
|
timeout: request_timeout, // 请求超时时间
|
|
|
- withCredentials: false, // 禁用 Cookie 等信息
|
|
|
|
|
|
|
+ withCredentials: false, // 禁用 Cookie 等信�?
|
|
|
// 自定义参数序列化函数
|
|
// 自定义参数序列化函数
|
|
|
paramsSerializer: (params) => {
|
|
paramsSerializer: (params) => {
|
|
|
return qs.stringify(params, { allowDots: true });
|
|
return qs.stringify(params, { allowDots: true });
|
|
|
},
|
|
},
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-// request拦截器
|
|
|
|
|
|
|
+// request拦截器?
|
|
|
service.interceptors.request.use(
|
|
service.interceptors.request.use(
|
|
|
(config: InternalAxiosRequestConfig) => {
|
|
(config: InternalAxiosRequestConfig) => {
|
|
|
config.headers["tenant-id"] = 1;
|
|
config.headers["tenant-id"] = 1;
|
|
|
- // 是否需要设置 token
|
|
|
|
|
|
|
+ // 是否需要设置token?
|
|
|
let isToken = (config!.headers || {}).isToken === false;
|
|
let isToken = (config!.headers || {}).isToken === false;
|
|
|
whiteList.some((v) => {
|
|
whiteList.some((v) => {
|
|
|
if (config.url && config.url.indexOf(v) > -1) {
|
|
if (config.url && config.url.indexOf(v) > -1) {
|
|
@@ -89,23 +86,23 @@ service.interceptors.request.use(
|
|
|
},
|
|
},
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
-// response 拦截器
|
|
|
|
|
|
|
+// response 拦截器?
|
|
|
service.interceptors.response.use(
|
|
service.interceptors.response.use(
|
|
|
async (response: AxiosResponse<any>) => {
|
|
async (response: AxiosResponse<any>) => {
|
|
|
let { data } = response;
|
|
let { data } = response;
|
|
|
const config = response.config;
|
|
const config = response.config;
|
|
|
if (!data) {
|
|
if (!data) {
|
|
|
- // 返回“[HTTP]请求没有返回值”;
|
|
|
|
|
|
|
+ // 返回“[HTTP]请求没有返回值?
|
|
|
throw new Error();
|
|
throw new Error();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 未设置状态码则默认成功状态
|
|
|
|
|
|
|
+ // 未设置状态码则默认成功状态?
|
|
|
// 二进制数据则直接返回,例如说 Excel 导出
|
|
// 二进制数据则直接返回,例如说 Excel 导出
|
|
|
if (
|
|
if (
|
|
|
response.request.responseType === "blob" ||
|
|
response.request.responseType === "blob" ||
|
|
|
response.request.responseType === "arraybuffer"
|
|
response.request.responseType === "arraybuffer"
|
|
|
) {
|
|
) {
|
|
|
- // 注意:如果导出的响应为 json,说明可能失败了,不直接返回进行下载
|
|
|
|
|
|
|
+ // 注意:如果导出的响应�?json,说明可能失败了,不直接返回进行下载
|
|
|
if (response.data.type !== "application/json") {
|
|
if (response.data.type !== "application/json") {
|
|
|
return response.data;
|
|
return response.data;
|
|
|
}
|
|
}
|
|
@@ -128,7 +125,7 @@ service.interceptors.response.use(
|
|
|
// 2. 进行刷新访问令牌
|
|
// 2. 进行刷新访问令牌
|
|
|
try {
|
|
try {
|
|
|
const refreshTokenRes = await refreshToken();
|
|
const refreshTokenRes = await refreshToken();
|
|
|
- // 2.1 刷新成功,则回放队列的请求 + 当前请求
|
|
|
|
|
|
|
+ // 2.1 刷新成功,则回放队列的请�?+ 当前请求
|
|
|
setToken((await refreshTokenRes).data.data);
|
|
setToken((await refreshTokenRes).data.data);
|
|
|
config.headers!.Authorization = "Bearer " + getAccessToken();
|
|
config.headers!.Authorization = "Bearer " + getAccessToken();
|
|
|
requestList.forEach((cb: any) => {
|
|
requestList.forEach((cb: any) => {
|
|
@@ -137,8 +134,8 @@ service.interceptors.response.use(
|
|
|
requestList = [];
|
|
requestList = [];
|
|
|
return service(config);
|
|
return service(config);
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
- // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
|
|
|
|
|
- // 2.2 刷新失败,只回放队列的请求
|
|
|
|
|
|
|
+ // 为什么需要?catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常�?
|
|
|
|
|
+ // 2.2 刷新失败,只回放队列的请求?
|
|
|
requestList.forEach((cb: any) => {
|
|
requestList.forEach((cb: any) => {
|
|
|
cb();
|
|
cb();
|
|
|
});
|
|
});
|
|
@@ -149,10 +146,10 @@ service.interceptors.response.use(
|
|
|
isRefreshToken = false;
|
|
isRefreshToken = false;
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
- // 添加到队列,等待刷新获取到新的令牌
|
|
|
|
|
|
|
+ // 添加到队列,等待刷新获取到新的令牌?
|
|
|
return new Promise((resolve) => {
|
|
return new Promise((resolve) => {
|
|
|
requestList.push(() => {
|
|
requestList.push(() => {
|
|
|
- config.headers!.Authorization = "Bearer " + getAccessToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
|
|
|
|
|
|
|
+ config.headers!.Authorization = "Bearer " + getAccessToken(); // 让每个请求携带自定义token 请根据实际情况自行修�?
|
|
|
resolve(service(config));
|
|
resolve(service(config));
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
@@ -187,7 +184,7 @@ service.interceptors.response.use(
|
|
|
if (message === "Network Error") {
|
|
if (message === "Network Error") {
|
|
|
message = "操作失败,系统异常!";
|
|
message = "操作失败,系统异常!";
|
|
|
} else if (message.includes("timeout")) {
|
|
} else if (message.includes("timeout")) {
|
|
|
- message = "接口请求超时,请刷新页面重试!";
|
|
|
|
|
|
|
+ message = "接口请求超时,请刷新页面重试";
|
|
|
} else if (message.includes("Request failed with status code")) {
|
|
} else if (message.includes("Request failed with status code")) {
|
|
|
message = "请求出错,请稍候重试" + message.substr(message.length - 3);
|
|
message = "请求出错,请稍候重试" + message.substr(message.length - 3);
|
|
|
}
|
|
}
|
|
@@ -209,12 +206,13 @@ const handleAuthorized = () => {
|
|
|
const isManualLogout = sessionStorage.getItem(manualLogoutKey) === "true";
|
|
const isManualLogout = sessionStorage.getItem(manualLogoutKey) === "true";
|
|
|
const isReloginCanceled = sessionStorage.getItem(reloginCancelKey) === "true";
|
|
const isReloginCanceled = sessionStorage.getItem(reloginCancelKey) === "true";
|
|
|
const ua = window.navigator.userAgent.toLowerCase();
|
|
const ua = window.navigator.userAgent.toLowerCase();
|
|
|
|
|
+ const isDingTalkEnv = ua.includes("dingtalk") || ua.includes("dingtalkwork");
|
|
|
if (isManualLogout || isReloginCanceled) {
|
|
if (isManualLogout || isReloginCanceled) {
|
|
|
deleteUserCache();
|
|
deleteUserCache();
|
|
|
removeToken();
|
|
removeToken();
|
|
|
|
|
|
|
|
if (!window.location.href.includes("login")) {
|
|
if (!window.location.href.includes("login")) {
|
|
|
- if (ua.includes("dingtalk") || ua.includes("dingtalkwork")) {
|
|
|
|
|
|
|
+ if (isDingTalkEnv) {
|
|
|
window.location.href = "/";
|
|
window.location.href = "/";
|
|
|
} else {
|
|
} else {
|
|
|
window.location.href = "/login";
|
|
window.location.href = "/login";
|
|
@@ -223,6 +221,14 @@ const handleAuthorized = () => {
|
|
|
return Promise.reject("登录超时,请重新登录");
|
|
return Promise.reject("登录超时,请重新登录");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if (isDingTalkEnv) {
|
|
|
|
|
+ deleteUserCache();
|
|
|
|
|
+ removeToken();
|
|
|
|
|
+ isRelogin.show = false;
|
|
|
|
|
+ window.location.href = "/";
|
|
|
|
|
+ return Promise.reject("登录超时,请重新登录");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (!isRelogin.show) {
|
|
if (!isRelogin.show) {
|
|
|
if (window.location.href.includes("login")) {
|
|
if (window.location.href.includes("login")) {
|
|
|
return Promise.reject("登录超时,请重新登录");
|
|
return Promise.reject("登录超时,请重新登录");
|
|
@@ -243,7 +249,7 @@ const handleAuthorized = () => {
|
|
|
removeToken();
|
|
removeToken();
|
|
|
isRelogin.show = false;
|
|
isRelogin.show = false;
|
|
|
|
|
|
|
|
- if (ua.includes("dingtalk") || ua.includes("dingtalkwork")) {
|
|
|
|
|
|
|
+ if (isDingTalkEnv) {
|
|
|
window.location.href = "/";
|
|
window.location.href = "/";
|
|
|
} else {
|
|
} else {
|
|
|
window.location.href = "/login";
|
|
window.location.href = "/login";
|
|
@@ -253,8 +259,8 @@ const handleAuthorized = () => {
|
|
|
sessionStorage.setItem(reloginCancelKey, "true");
|
|
sessionStorage.setItem(reloginCancelKey, "true");
|
|
|
deleteUserCache(); // 删除用户缓存
|
|
deleteUserCache(); // 删除用户缓存
|
|
|
removeToken();
|
|
removeToken();
|
|
|
- isRelogin.show = false; // 重置显示状态
|
|
|
|
|
- if (ua.includes("dingtalk") || ua.includes("dingtalkwork")) {
|
|
|
|
|
|
|
+ isRelogin.show = false; // 重置显示状?
|
|
|
|
|
+ if (isDingTalkEnv) {
|
|
|
window.location.href = "/";
|
|
window.location.href = "/";
|
|
|
} else {
|
|
} else {
|
|
|
window.location.href = "/login";
|
|
window.location.href = "/login";
|