import axios from 'axios' import { isWebView2 } from './env' // WebView2 自定义协议前缀 const WEBVIEW2_BASE = 'app://api/' // Vite 开发页走 5206 API;API 托管前端时使用同源地址。 const isViteDevServer = window.location.port === '51552' const HTTP_ORIGIN = isViteDevServer ? `${window.location.protocol}//${window.location.hostname || 'localhost'}:5206` : window.location.origin const HTTP_BASE = `${HTTP_ORIGIN}/api/` export const apiOrigin = (): string => HTTP_ORIGIN export const apiUrl = (path: string): string => { if (/^https?:\/\//i.test(path)) return path const normalized = path.startsWith('/') ? path : `/${path}` return `${isWebView2() ? '' : HTTP_ORIGIN}${normalized}` } // ─── axios 实例 ──────────────────────────────────────────────────────────────── const http = axios.create({ headers: { 'Content-Type': 'application/json' }, }) // 请求拦截器:仅在浏览器环境下注入鉴权 Token // WebView2 本地运行,不需要鉴权 http.interceptors.request.use((config) => { if (!isWebView2()) { const token = localStorage.getItem('authToken') if (token) { config.headers.Authorization = `Bearer ${token}` } } return config }) // 响应拦截器:统一解包 C# 返回的 { success, data/error } 结构 // C# BuildSuccessResponseBody 固定格式:{ "success": true, "data": ... } // 错误格式:{ "success": false, "error": "..." } // WebView2 桥接和 HTTP 两个环境返回结构相同,拦截器可统一处理 http.interceptors.response.use( (response) => { const payload = response.data as { success: boolean; data?: unknown; error?: string; message?: string } if (payload?.success === false) { return Promise.reject(new Error(payload.error ?? payload.message ?? '请求失败')) } return (payload?.data ?? payload) as never }, (error) => { const msg: string = error.response?.data?.error ?? error.response?.data?.message ?? error.message ?? '网络错误' return Promise.reject(new Error(msg)) }, ) // ─── 统一请求方法 ────────────────────────────────────────────────────────────── interface RequestOptions { method?: string headers?: Record body?: unknown } export async function request(endpoint: string, options: RequestOptions = {}): Promise { const url = (isWebView2() ? WEBVIEW2_BASE : HTTP_BASE) + endpoint // WebView2:直接走桥接 fetch(桥接脚本已完整覆盖 window.fetch) if (isWebView2()) { const res = await fetch(url, { method: options.method ?? 'GET', headers: { 'Content-Type': 'application/json', ...(options.headers ?? {}) }, body: options.body !== undefined ? JSON.stringify(options.body) : undefined, }) const payload = await res.json() as { success: boolean; data?: T; error?: string; message?: string } if (payload?.success === false) { throw new Error(payload.error ?? payload.message ?? '请求失败') } return (payload?.data ?? payload) as T } // 普通浏览器:走 axios(拦截器处理鉴权和响应解包) return http.request({ url, method: options.method ?? 'GET', headers: options.headers, data: options.body, }) as Promise }