// 连接健康度校验文件 可从多个连接中筛选符合条件的链接并设置为全局连接 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} 请求响应 */ 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} 可用的 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} 可用的服务基础地址(失败则抛出异常) */ 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; } };