661e417619
- Move src/data/{api,dto,schemas} directories to src/data/services/*
- Update all relative imports across the codebase to reference new paths
- Use CSS color tokens for splash button gradient in splash-button.module.css
- Add responsive sizes attribute to splash background image
- Add JSDoc documentation to splash-background component referencing original Dart implementation
86 lines
2.3 KiB
TypeScript
86 lines
2.3 KiB
TypeScript
/**
|
|
* 日志拦截器
|
|
*
|
|
* 在开发模式下记录请求/响应/错误日志。
|
|
* 原始 Dart: lib/core/net/interceptor/app_interceptor.dart 中的日志部分。
|
|
*/
|
|
import type { FetchHook } from "ofetch";
|
|
|
|
const TAG = "[API]";
|
|
|
|
function isDev(): boolean {
|
|
return process.env.NODE_ENV !== "production";
|
|
}
|
|
|
|
function getRequestUrl(request: Request | string): string {
|
|
return typeof request === "string" ? request : request.url;
|
|
}
|
|
|
|
function getRequestMethod(
|
|
request: Request | string,
|
|
options: { method?: string }
|
|
): string {
|
|
return request instanceof Request ? request.method : options.method ?? "GET";
|
|
}
|
|
|
|
function formatBody(body: unknown): string {
|
|
if (body === undefined || body === null) return "";
|
|
try {
|
|
if (body instanceof FormData) {
|
|
const entries: string[] = [];
|
|
body.forEach((value, key) => {
|
|
if (value instanceof File) {
|
|
entries.push(`${key}=File(${value.name})`);
|
|
} else {
|
|
entries.push(`${key}=${String(value)}`);
|
|
}
|
|
});
|
|
return `FormData{${entries.join(", ")}}`;
|
|
}
|
|
return JSON.stringify(body);
|
|
} catch {
|
|
return String(body);
|
|
}
|
|
}
|
|
|
|
export const onRequestLogging: FetchHook = async (ctx) => {
|
|
if (!isDev()) return;
|
|
const method = getRequestMethod(ctx.request, ctx.options);
|
|
const url = getRequestUrl(ctx.request);
|
|
console.log(
|
|
`${TAG} → ${method} ${url}`,
|
|
ctx.options.body !== undefined ? formatBody(ctx.options.body) : ""
|
|
);
|
|
};
|
|
|
|
export const onResponseLogging: FetchHook = async (ctx) => {
|
|
if (!isDev() || !ctx.response) return;
|
|
const method = getRequestMethod(ctx.request, ctx.options);
|
|
const url = getRequestUrl(ctx.request);
|
|
console.log(
|
|
`${TAG} ← ${ctx.response.status} ${method} ${url}`,
|
|
formatBody(ctx.response._data)
|
|
);
|
|
};
|
|
|
|
export const onErrorLogging: FetchHook = async (ctx) => {
|
|
if (!isDev()) return;
|
|
const status = ctx.response?.status ?? "N/A";
|
|
const method = getRequestMethod(ctx.request, ctx.options);
|
|
const url = getRequestUrl(ctx.request);
|
|
console.error(
|
|
`${TAG} ✕ ${status} ${method} ${url}`,
|
|
ctx.error?.message ?? "Unknown error"
|
|
);
|
|
};
|
|
|
|
/**
|
|
* 兼容旧接口的 FetchHooks 形式(保留以备兼容)
|
|
*/
|
|
export const loggingInterceptor = {
|
|
onRequest: onRequestLogging,
|
|
onResponse: onResponseLogging,
|
|
onResponseError: onErrorLogging,
|
|
onRequestError: onErrorLogging,
|
|
};
|