mirror of
https://github.com/stardrophere/InsightRadar.git
synced 2026-06-05 23:07:51 +08:00
修改前端请求配置
This commit is contained in:
@@ -1,123 +1,12 @@
|
|||||||
/**
|
|
||||||
* API 基础配置:自动探测内网/公网后端,失败时回退公网
|
|
||||||
*/
|
|
||||||
const API_PREFIX = '/api/v1'
|
const API_PREFIX = '/api/v1'
|
||||||
const LAN_BACKEND_ORIGIN = import.meta.env.VITE_BACKEND_ORIGIN
|
|
||||||
const PUBLIC_BACKEND_ORIGIN = import.meta.env.VITE_BACKEND_ORIGIN
|
|
||||||
const PROBE_TIMEOUT_MS = 1200
|
|
||||||
|
|
||||||
console.log(LAN_BACKEND_ORIGIN);
|
export function buildUrl(path: string): string {
|
||||||
|
if (!path.startsWith('/')) {
|
||||||
const LAN_API_BASE_URL = `${LAN_BACKEND_ORIGIN}${API_PREFIX}`
|
path = '/' + path
|
||||||
const PUBLIC_API_BASE_URL = `${PUBLIC_BACKEND_ORIGIN}${API_PREFIX}`
|
|
||||||
const ENV_API_BASE_URL = import.meta.env.VITE_API_BASE_URL as string | undefined
|
|
||||||
|
|
||||||
const EXPECTED_OPENAPI_PATHS = ['/api/v1/auth/login', '/api/v1/events/unified']
|
|
||||||
|
|
||||||
let detectedApiBaseUrl: string | null = ENV_API_BASE_URL ?? null
|
|
||||||
let detectPromise: Promise<string> | null = null
|
|
||||||
|
|
||||||
function normalizePath(path: string): string {
|
|
||||||
if (!path) return '/'
|
|
||||||
return path.startsWith('/') ? path : `/${path}`
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildUrl(base: string, path: string): string {
|
|
||||||
return `${base}${normalizePath(path)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPrivateIpv4(hostname: string): boolean {
|
|
||||||
const parts = hostname.split('.').map((part) => Number.parseInt(part, 10))
|
|
||||||
if (parts.length !== 4 || parts.some((part) => Number.isNaN(part) || part < 0 || part > 255)) {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
return `${API_PREFIX}${path}`
|
||||||
const a = parts[0] as number
|
|
||||||
const b = parts[1] as number
|
|
||||||
if (a === 10) return true
|
|
||||||
if (a === 172 && b >= 16 && b <= 31) return true
|
|
||||||
if (a === 192 && b === 168) return true
|
|
||||||
if (a === 127) return true
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isLanHostname(hostname: string): boolean {
|
export async function fetchApi(path: string, init?: RequestInit) {
|
||||||
const normalized = hostname.toLowerCase()
|
return fetch(buildUrl(path), init)
|
||||||
if (normalized === 'localhost' || normalized.endsWith('.local')) return true
|
|
||||||
return isPrivateIpv4(normalized)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 探测内网后端是否可用(请求 openapi.json)
|
|
||||||
async function probeLanBackend(): Promise<boolean> {
|
|
||||||
if (typeof window === 'undefined') return false
|
|
||||||
|
|
||||||
const controller = new AbortController()
|
|
||||||
const timeout = window.setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS)
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${LAN_BACKEND_ORIGIN}/openapi.json`, {
|
|
||||||
method: 'GET',
|
|
||||||
cache: 'no-store',
|
|
||||||
signal: controller.signal,
|
|
||||||
})
|
|
||||||
if (!response.ok) return false
|
|
||||||
|
|
||||||
const data = (await response.json()) as { paths?: Record<string, unknown> }
|
|
||||||
const paths = data.paths
|
|
||||||
if (!paths || typeof paths !== 'object') return false
|
|
||||||
|
|
||||||
return EXPECTED_OPENAPI_PATHS.every((path) =>
|
|
||||||
Object.prototype.hasOwnProperty.call(paths, path),
|
|
||||||
)
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
} finally {
|
|
||||||
window.clearTimeout(timeout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据当前 hostname 与探测结果选择内网或公网 API 地址
|
|
||||||
async function detectApiBaseUrl(): Promise<string> {
|
|
||||||
if (ENV_API_BASE_URL) return ENV_API_BASE_URL
|
|
||||||
if (typeof window === 'undefined') return PUBLIC_API_BASE_URL
|
|
||||||
|
|
||||||
if (!isLanHostname(window.location.hostname)) {
|
|
||||||
return PUBLIC_API_BASE_URL
|
|
||||||
}
|
|
||||||
|
|
||||||
const canUseLan = await probeLanBackend()
|
|
||||||
return canUseLan ? LAN_API_BASE_URL : PUBLIC_API_BASE_URL
|
|
||||||
}
|
|
||||||
|
|
||||||
function isLikelyNetworkError(error: unknown): boolean {
|
|
||||||
return error instanceof TypeError || (error instanceof DOMException && error.name === 'AbortError')
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getApiBaseUrl(): Promise<string> {
|
|
||||||
if (detectedApiBaseUrl) return detectedApiBaseUrl
|
|
||||||
if (!detectPromise) {
|
|
||||||
detectPromise = detectApiBaseUrl()
|
|
||||||
.then((url) => {
|
|
||||||
detectedApiBaseUrl = url
|
|
||||||
return url
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
detectPromise = null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return detectPromise
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function fetchApi(path: string, init?: RequestInit): Promise<Response> {
|
|
||||||
const apiBaseUrl = await getApiBaseUrl()
|
|
||||||
const requestUrl = buildUrl(apiBaseUrl, path)
|
|
||||||
|
|
||||||
try {
|
|
||||||
return await fetch(requestUrl, init)
|
|
||||||
} catch (error) {
|
|
||||||
if (!ENV_API_BASE_URL && apiBaseUrl === LAN_API_BASE_URL && isLikelyNetworkError(error)) {
|
|
||||||
detectedApiBaseUrl = PUBLIC_API_BASE_URL
|
|
||||||
return fetch(buildUrl(PUBLIC_API_BASE_URL, path), init)
|
|
||||||
}
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user