Files
aiartstudio/server/utils/fetch.ts
T
2026-04-26 01:13:38 +08:00

102 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// server/utils/fetch.ts - NewAPI 请求封装:集中维护 baseURL、raw fetch 和服务端鉴权请求。
import type { H3Event } from "h3";
import { createError, getCookie } from "h3";
import {
NEWAPI_SESSION_COOKIE,
NEWAPI_USER_ID_COOKIE
} from "~~/server/utils/newApiAuthCookies";
/** 上游 NewAPI 服务的根地址,只在这里维护一次 */
const BASE_URL = "https://api.qflink.xyz";
type FetchOptions = Parameters<typeof $fetch>[1];
type FetchHeaders = HeadersInit | undefined;
interface INewApiRawResponse<T> {
/** 上游响应 bodyofetch raw response 使用 _data 保存解析后的 body */
_data?: T;
/** 上游响应头,登录时需要从 Set-Cookie 中提取 session */
headers: Headers;
}
/**
* 向上游 NewAPI 发起请求
*
* @param path 相对路径,如 "/api/user/register",会自动拼接到 BASE_URL 后面
* @param options 透传给 $fetch 的所有选项(method、body、headers 等)
* @returns Promise<T>T 是上游返回的数据类型
*
* @example
* const result = await newApiFetch<string>("/api/user/register", {
* method: "POST",
* body: { username: "xxx" }
* })
*/
export const newApiFetch = <T>(
path: string,
options?: FetchOptions
): Promise<T> => {
return $fetch<T>(path, {
baseURL: BASE_URL,
...options
}) as Promise<T>;
};
/**
* 向上游 NewAPI 发起请求,并保留响应头。
*
* 仅在登录这类需要读取 Set-Cookie 的场景使用;普通业务请求继续用
* newApiFetch,保证上游请求入口仍然集中在本文件。
*/
export const newApiFetchRaw = async <T>(
path: string,
options?: FetchOptions
): Promise<INewApiRawResponse<T>> => {
const res = await $fetch.raw<T>(path, {
baseURL: BASE_URL,
...options
});
return {
_data: res._data as T | undefined,
headers: res.headers
};
};
/**
* 向上游 NewAPI 发起已登录请求。
*
* 前端不读取 NewAPI session;这里只在 Nuxt server 内从本站 httpOnly
* cookie 读取 session/userId,并按 NewAPI 要求补齐 Cookie 与 New-Api-User。
*/
export const newApiAuthedFetch = <T>(
event: H3Event,
path: string,
options?: FetchOptions
): Promise<T> => {
const session = getCookie(event, NEWAPI_SESSION_COOKIE);
const userId = getCookie(event, NEWAPI_USER_ID_COOKIE);
if (!session || !userId) {
throw createError({
statusCode: 401,
statusMessage: "未登录"
});
}
return newApiFetch<T>(path, {
...options,
headers: {
...normalizeHeaders(options?.headers),
Cookie: `session=${session}`,
"New-Api-User": userId
}
});
};
/** 归一化调用方 headers,追加鉴权头时不丢失已有 Content-Type */
const normalizeHeaders = (headers: FetchHeaders) => {
if (!headers) return {};
return Object.fromEntries(new Headers(headers).entries());
};