275 lines
7.2 KiB
JavaScript
Raw Normal View History

2026-01-20 19:36:49 +08:00
import { loading, hideLoading } from "./widget";
2026-09-22 17:07:16 +08:00
import { buildApiUrl, getDefaultUploadUrl, isSh6CorpId, normalizeCorpId, resolveApiContext } from "./api-base-config";
2026-01-20 19:36:49 +08:00
const defaultOptions = {
header: {
"Content-Type": "application/json",
},
method: "POST",
timeout: 1000 * 60, // 请求超时设置为60秒
};
const tasks = [];
2026-09-22 17:07:16 +08:00
let miniappSessionRefresher = null;
let miniappSessionRefreshPromise = null;
export function setMiniappSessionRefresher(refresher) {
miniappSessionRefresher = typeof refresher === "function" ? refresher : null;
}
async function refreshMiniappSession() {
if (!miniappSessionRefresher) return false;
if (!miniappSessionRefreshPromise) {
miniappSessionRefreshPromise = Promise.resolve()
.then(() => miniappSessionRefresher())
.finally(() => {
miniappSessionRefreshPromise = null;
});
}
await miniappSessionRefreshPromise;
return Boolean(uni.getStorageSync("miniappSessionToken"));
}
2026-01-20 19:36:49 +08:00
// 是否正在刷新 token
let isRefreshing = false;
// 重试队列
let retryQueue = [];
/**
* 处理重试队列
* @param {String} token - 新的 token
*/
function processQueue(token) {
retryQueue.forEach(({ resolve, reject, config }) => {
if (token) {
// 更新 token 并重试请求
if (!config.header) config.header = {};
config.header.Authorization = `Bearer ${token}`;
uni.request({
...config,
success: (res) => resolve(res),
fail: (err) => reject(err),
});
} else {
reject(new Error("Token 刷新失败"));
}
});
retryQueue = [];
}
/**
* 刷新 token
* @returns {Promise<String|null>}
*/
async function refreshAccessToken() {
const refreshToken = uni.getStorageSync("refreshToken");
if (!refreshToken) {
return null;
}
if (isRefreshing) {
// 等待刷新完成
await new Promise((resolve) => setTimeout(resolve, 100));
return uni.getStorageSync("accessToken");
}
isRefreshing = true;
try {
const res = await uni.request({
2026-06-03 10:07:43 +08:00
url: buildApiUrl("/auth/refresh"),
2026-01-20 19:36:49 +08:00
method: "POST",
header: {
"Content-Type": "application/json",
},
data: {
refreshToken,
},
});
if (res && res.data && res.data.success && res.data.data) {
const newToken = res.data.data.accessToken;
uni.setStorageSync("accessToken", newToken);
processQueue(newToken);
return newToken;
} else {
// 刷新失败,清空队列
processQueue(null);
// 清除登录状态
uni.removeStorageSync("accessToken");
uni.removeStorageSync("refreshToken");
uni.removeStorageSync("jwtUserInfo");
return null;
}
} catch (error) {
console.error("Token 刷新异常:", error);
processQueue(null);
uni.removeStorageSync("accessToken");
uni.removeStorageSync("refreshToken");
uni.removeStorageSync("jwtUserInfo");
return null;
} finally {
isRefreshing = false;
}
}
const request = async (options = {}, showLoading = true) => {
2026-09-22 17:07:16 +08:00
const sessionRetried = options.__miniappSessionRetried === true;
const requestOptions = { ...options };
delete requestOptions.__miniappSessionRetried;
2026-01-20 19:36:49 +08:00
// 合并用户传入的配置和默认配置
2026-09-22 17:07:16 +08:00
if (!requestOptions.data) requestOptions.data = {};
if (requestOptions.data.corpId) {
requestOptions.data = {
...requestOptions.data,
corpId: normalizeCorpId(requestOptions.data.corpId),
2026-06-11 18:13:49 +08:00
};
}
2026-09-22 17:07:16 +08:00
const requestCorpId = requestOptions.data.corpId || resolveApiContext().corpId;
const requiresMiniappSession = isSh6CorpId(requestCorpId);
2026-01-20 19:36:49 +08:00
const config = {
...defaultOptions,
2026-09-22 17:07:16 +08:00
...requestOptions,
url: buildApiUrl(requestOptions.url, requestOptions.data.corpId),
2026-01-20 19:36:49 +08:00
};
2026-09-22 17:07:16 +08:00
const sessionToken = uni.getStorageSync("miniappSessionToken");
if (requiresMiniappSession && sessionToken) {
config.header = { ...(config.header || {}), "X-Miniapp-Session": sessionToken };
}
2026-01-20 19:36:49 +08:00
const key = `${JSON.stringify(config)}_${Date.now()}`;
if (showLoading) {
recordTask(key)
}
try {
// 发起请求
const res = await uni.request(config);
if (showLoading) {
removeTask(key)
}
2026-09-22 17:07:16 +08:00
if (requiresMiniappSession && res.statusCode === 401) {
uni.removeStorageSync("miniappSessionToken");
uni.removeStorageSync("miniappSessionExpiresAt");
if (
!sessionRetried &&
requestOptions.data.type !== "wxAppLogin" &&
await refreshMiniappSession()
) {
return request({ ...requestOptions, __miniappSessionRetried: true }, showLoading);
}
}
2026-01-20 19:36:49 +08:00
// 如果返回 401,尝试刷新 token
// if (res.statusCode === 401) {
// if (showLoading) {
// removeTask(key)
// }
// // 尝试刷新 token
// const newToken = await refreshAccessToken();
// if (newToken) {
// // 刷新成功,重试原请求
// if (!config.header) config.header = {};
// config.header.Authorization = `Bearer ${newToken}`;
// if (showLoading) {
// recordTask(key)
// }
// const retryRes = await uni.request(config);
// if (showLoading) {
// removeTask(key)
// }
// const success = retryRes && retryRes.data && retryRes.data.success === true;
// if (success) {
// return retryRes.data;
// }
// return {
// success: false,
// message: retryRes.data && retryRes.data.message ? retryRes.data.message : "请求失败",
// };
// } else {
// return {
// success: false,
// message: "登录已过期,请重新登录",
// };
// }
// }
const success = res && res.data && res.data.success === true;
if (success) {
return res.data;
}
return {
2026-08-31 09:14:04 +08:00
...(res && res.data && typeof res.data === "object" ? res.data : {}),
2026-01-20 19:36:49 +08:00
success: false,
message: res.data && res.data.message ? res.data.message : "请求失败",
};
} catch (error) {
console.log("error:", error);
if (showLoading) {
removeTask(key)
}
return Promise.reject(error);
}
};
function recordTask(task) {
if (tasks.length === 0) {
loading("请求中...");
}
tasks.push(task);
}
function removeTask(task) {
const index = tasks.findIndex((i) => i === task);
if (index > -1) {
tasks.splice(index, 1);
}
if (tasks.length === 0) {
hideLoading();
}
}
export default request;
2026-06-03 10:07:43 +08:00
export const uploadUrl = getDefaultUploadUrl();
2026-01-20 19:36:49 +08:00
2026-06-03 10:07:43 +08:00
export function getFullPath(path, corpId) {
2026-06-11 18:13:49 +08:00
return buildApiUrl(path, normalizeCorpId(corpId));
2026-01-20 19:36:49 +08:00
}
2026-06-03 10:07:43 +08:00
export function upload(path, corpId) {
2026-06-11 18:13:49 +08:00
const normalizedCorpId = normalizeCorpId(corpId);
2026-09-22 17:07:16 +08:00
const uploadCorpId = normalizedCorpId || resolveApiContext().corpId;
const sessionToken = uni.getStorageSync("miniappSessionToken");
2026-06-11 18:13:49 +08:00
const currentUploadUrl = buildApiUrl("/upload", normalizedCorpId);
2026-01-20 19:36:49 +08:00
return new Promise((resolve) => {
uni.uploadFile({
2026-06-03 10:07:43 +08:00
url: currentUploadUrl,
2026-09-22 17:07:16 +08:00
header: isSh6CorpId(uploadCorpId) && sessionToken
? { "X-Miniapp-Session": sessionToken }
: {},
2026-01-20 19:36:49 +08:00
filePath: path,
name: 'file',
fileType: 'image',
success: (res) => {
try {
const url = JSON.parse(res.data).filePath;
2026-06-11 18:13:49 +08:00
resolve(url ? getFullPath(url, normalizedCorpId) : '')
2026-01-20 19:36:49 +08:00
} catch (e) {
resolve()
}
},
fail: res => {
resolve()
}
})
})
}