// 连接健康度校验文件 可从多个连接中筛选符合条件的链接并设置为全局连接
|
export const serviceList = [
|
{
|
name: "API_INNER",
|
baseUrl: process.env.VUE_APP_BASE_API_INNER || process.env.VUE_APP_BASE_API, // 内网地址, 没有的情况下,就使用外网地址
|
healthPath: "/Health",
|
},
|
{
|
name: "API_OUTER",
|
baseUrl: process.env.VUE_APP_BASE_API, // 外网地址
|
healthPath: "/Health",
|
},
|
];
|
|
/**
|
* 带超时控制的 fetch 请求封装
|
* @param {string} url 请求地址
|
* @param {Object} options fetch 配置
|
* @param {number} timeout 超时时间(毫秒),默认 3000ms
|
* @returns {Promise<Response>} 请求响应
|
*/
|
const fetchWithTimeout = async (url, options = {}, timeout = 3000) => {
|
// 1. 创建中止控制器,用于超时取消请求
|
const controller = new AbortController();
|
const signal = controller.signal;
|
|
// 2. 超时定时器:到时间后中止请求并抛出错误
|
const timeoutTimer = setTimeout(() => {
|
controller.abort();
|
throw new Error(`请求超时(${timeout}ms)`);
|
}, timeout);
|
|
try {
|
// 3. 绑定中止信号到 fetch 请求
|
const response = await fetch(url, {
|
...options,
|
signal, // 关键:关联中止控制器
|
});
|
clearTimeout(timeoutTimer); // 请求成功,清除超时定时器
|
return response;
|
} catch (error) {
|
clearTimeout(timeoutTimer); // 出错/超时,清除定时器
|
// 区分中止错误(超时)和其他错误
|
if (error.name === 'AbortError') {
|
throw new Error(`请求超时:${url} 超过 ${timeout}ms 未响应`);
|
}
|
throw error; // 抛出其他错误(如网络错误)
|
}
|
};
|
|
/**
|
* 检测单个服务健康状态(新增超时控制)
|
* @param {Object} service - 服务配置(baseUrl + healthPath)
|
* @returns {Promise<String|null>} 可用的 baseUrl,失败返回 null
|
*/
|
export const checkServiceHealth = async (service) => {
|
const { baseUrl, healthPath } = service;
|
if (!baseUrl) return null;
|
|
try {
|
// 健康检查请求(使用封装的带超时的 fetch,3秒超时)
|
const response = await fetchWithTimeout(
|
`${baseUrl}${healthPath}`,
|
{
|
method: "GET",
|
headers: {
|
"Content-Type": "application/json",
|
},
|
},
|
3000 // 明确配置 3 秒超时
|
);
|
|
if (response.ok) {
|
console.log(`服务 ${service.name} 健康,地址:${baseUrl}`);
|
return baseUrl;
|
} else {
|
// 响应状态码非 2xx,视为服务不可用
|
console.warn(`服务 ${service.name} 响应异常,状态码:${response.status}`);
|
return null;
|
}
|
} catch (error) {
|
console.error(`服务 ${service.name} 连接失败:`, error.message);
|
return null;
|
}
|
};
|
|
/**
|
* 批量检测所有服务,返回第一个可用的 baseUrl
|
* @returns {Promise<String>} 可用的服务基础地址(失败则抛出异常)
|
*/
|
export const findAvailableService = async () => {
|
// 并行检测所有服务(提高效率)
|
try {
|
const healthCheckPromises = serviceList.map((item) => {
|
return checkServiceHealth(item);
|
});
|
const healthResult = await Promise.all(healthCheckPromises);
|
// 筛选可用的 baseUrl
|
console.log("健康检查结果:", healthResult);
|
const availableBaseUrl = healthResult.filter((item) => item != null)[0];
|
|
if (availableBaseUrl) {
|
return availableBaseUrl;
|
} else {
|
// 所有服务均不可用,抛出异常
|
throw new Error("所有服务健康检查失败,请检查服务状态或网络配置");
|
}
|
} catch (err) {
|
throw err;
|
}
|
};
|