57 lines
1.5 KiB
TypeScript
57 lines
1.5 KiB
TypeScript
import { getSession } from "next-auth/react";
|
||
import type { Session } from "next-auth";
|
||
|
||
export const API_BASE = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000";
|
||
|
||
export function getApiUrl(path: string): string {
|
||
return `${API_BASE}${path}`;
|
||
}
|
||
|
||
export async function fetchWithAuth(
|
||
url: string,
|
||
options: RequestInit = {},
|
||
token?: string
|
||
) {
|
||
// 如果没有显式传入 token,尝试从 NextAuth session 获取
|
||
let authToken = token;
|
||
if (!authToken && typeof window !== "undefined") {
|
||
try {
|
||
const session = await getSession();
|
||
authToken = (session as Session)?.accessToken;
|
||
} catch {
|
||
// ignore session fetch error
|
||
}
|
||
}
|
||
|
||
const headers: Record<string, string> = {
|
||
"Content-Type": "application/json",
|
||
...((options.headers as Record<string, string>) || {}),
|
||
};
|
||
if (authToken) {
|
||
headers["Authorization"] = `Bearer ${authToken}`;
|
||
}
|
||
const res = await fetch(`${API_BASE}${url}`, { ...options, headers });
|
||
|
||
if (res.status === 401) {
|
||
// 不要自动跳转登录页,让页面组件/layout自行处理认证状态
|
||
throw new Error("登录已过期,请重新登录");
|
||
}
|
||
|
||
if (!res.ok) {
|
||
let errorDetail = `请求失败 (HTTP ${res.status})`;
|
||
try {
|
||
const error = await res.json();
|
||
errorDetail = error.detail || error.message || errorDetail;
|
||
} catch {
|
||
// 解析失败,使用默认错误信息
|
||
}
|
||
throw new Error(errorDetail);
|
||
}
|
||
|
||
if (res.status === 204) {
|
||
return null;
|
||
}
|
||
|
||
return res.json();
|
||
}
|