67 lines
2.4 KiB
TypeScript
67 lines
2.4 KiB
TypeScript
const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001/api/v1';
|
||
|
||
let apiAvailable: boolean | null = null;
|
||
let probePromise: Promise<boolean> | null = null;
|
||
|
||
async function checkApi(): Promise<boolean> {
|
||
if (apiAvailable !== null) return apiAvailable;
|
||
if (probePromise) return probePromise;
|
||
probePromise = (async () => {
|
||
try {
|
||
// 探测一个不依赖数据库的端点(/config/ai 总是返回 200,只要 NestJS 起来了)
|
||
const res = await fetch(`${API_BASE}/config/ai`, { method: 'GET', signal: AbortSignal.timeout(1500) });
|
||
apiAvailable = res.ok;
|
||
} catch {
|
||
apiAvailable = false;
|
||
}
|
||
return apiAvailable;
|
||
})();
|
||
return probePromise;
|
||
}
|
||
|
||
async function request<T>(path: string, options?: RequestInit): Promise<T> {
|
||
const available = await checkApi();
|
||
if (!available) throw new Error('API 不可用');
|
||
const res = await fetch(`${API_BASE}${path}`, {
|
||
headers: { 'Content-Type': 'application/json', ...options?.headers },
|
||
...options,
|
||
}).catch(() => null);
|
||
if (!res) throw new Error('API 不可用');
|
||
if (!res.ok) {
|
||
const error = await res.json().catch(() => ({}));
|
||
throw new Error(error.message || `请求失败: ${res.status}`);
|
||
}
|
||
return res.json();
|
||
}
|
||
|
||
export const api = {
|
||
get: <T>(path: string) => request<T>(path),
|
||
post: <T>(path: string, data: unknown) =>
|
||
request<T>(path, { method: 'POST', body: JSON.stringify(data) }),
|
||
put: <T>(path: string, data: unknown) =>
|
||
request<T>(path, { method: 'PUT', body: JSON.stringify(data) }),
|
||
patch: <T>(path: string, data: unknown) =>
|
||
request<T>(path, { method: 'PATCH', body: JSON.stringify(data) }),
|
||
delete: <T>(path: string) => request<T>(path, { method: 'DELETE' }),
|
||
postRaw: async <T>(path: string, data: unknown, timeoutMs = 120000): Promise<T> => {
|
||
// 调用 AI 类长耗时接口时使用,跳过 checkApi 短路(确保走真实请求)
|
||
const controller = new AbortController();
|
||
const tid = setTimeout(() => controller.abort(), timeoutMs);
|
||
try {
|
||
const res = await fetch(`${API_BASE}${path}`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(data),
|
||
signal: controller.signal,
|
||
});
|
||
if (!res.ok) {
|
||
const err = await res.json().catch(() => ({}));
|
||
throw new Error(err.message || `请求失败: ${res.status}`);
|
||
}
|
||
return res.json();
|
||
} finally {
|
||
clearTimeout(tid);
|
||
}
|
||
},
|
||
};
|