refactor(api): improve http client implementation
- Removed redundant comments and code annotations - Simplified type definitions and interface declarations - Streamlined URL construction logic - Enhanced body handling for FormData and JSON payloads - Optimized header normalization process - Cleaned up API method signatures - Improved content-type handling for form data - Removed unnecessary blank lines and formatting clutter
This commit is contained in:
@@ -1,11 +1,8 @@
|
|||||||
// src/lib/api/httpClient.ts
|
|
||||||
|
|
||||||
import { browser } from '$app/environment'; // SvelteKit 环境变量
|
import { browser } from '$app/environment';
|
||||||
import { log } from '$lib/log.ts';
|
import { log } from '$lib/log.ts';
|
||||||
|
|
||||||
// 1. 完善类型定义,确保 FormData 被允许
|
|
||||||
// 假设 JsonValue 和 JsonObject 在你的 types/http.ts 中定义
|
|
||||||
// 这里为了示例完整性,我做了一个简单的宽泛定义,你可以替换回你的 import
|
|
||||||
type JsonValue = string | number | boolean | null | JsonObject | JsonValue[];
|
type JsonValue = string | number | boolean | null | JsonObject | JsonValue[];
|
||||||
interface JsonObject { [key: string]: JsonValue }
|
interface JsonObject { [key: string]: JsonValue }
|
||||||
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD';
|
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD';
|
||||||
@@ -16,15 +13,13 @@ export interface ApiResult<T> {
|
|||||||
data: T;
|
data: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 扩展 RequestOptions 以支持 SvelteKit 的 custom fetch
|
|
||||||
interface RequestOptions extends Omit<RequestInit, 'method' | 'body'> {
|
interface RequestOptions extends Omit<RequestInit, 'method' | 'body'> {
|
||||||
body?: JsonObject | FormData | object;
|
body?: JsonObject | FormData | object;
|
||||||
customFetch?: typeof fetch; // 允许传入 SvelteKit 的 load fetch
|
customFetch?: typeof fetch;
|
||||||
}
|
}
|
||||||
|
|
||||||
const API_BASE_URL = import.meta.env.VITE_PUBLIC_API_URL || 'http://localhost:18888/api';
|
const API_BASE_URL = import.meta.env.VITE_PUBLIC_API_URL || 'http://localhost:18888/api';
|
||||||
|
|
||||||
// 辅助函数:规范化 Headers
|
|
||||||
const normalizeHeaders = (headers?: HeadersInit): Record<string, string> => {
|
const normalizeHeaders = (headers?: HeadersInit): Record<string, string> => {
|
||||||
const result: Record<string, string> = {};
|
const result: Record<string, string> = {};
|
||||||
if (!headers) return result;
|
if (!headers) return result;
|
||||||
@@ -65,10 +60,8 @@ const httpRequest = async <T>(
|
|||||||
method: HttpMethod,
|
method: HttpMethod,
|
||||||
options: RequestOptions = {}
|
options: RequestOptions = {}
|
||||||
): Promise<ApiResult<T>> => {
|
): Promise<ApiResult<T>> => {
|
||||||
// 拼接 URL
|
|
||||||
const fullUrl = url.startsWith('http') ? url : `${API_BASE_URL}${url}`;
|
const fullUrl = url.startsWith('http') ? url : `${API_BASE_URL}${url}`;
|
||||||
|
|
||||||
// 2. 提取 customFetch,优先使用传入的 fetch (解决 SSR Cookie 问题)
|
|
||||||
const { body, headers, customFetch, ...rest } = options;
|
const { body, headers, customFetch, ...rest } = options;
|
||||||
const fetchImpl = customFetch || fetch;
|
const fetchImpl = customFetch || fetch;
|
||||||
|
|
||||||
@@ -77,14 +70,11 @@ const httpRequest = async <T>(
|
|||||||
|
|
||||||
const canHaveBody = method !== 'GET' && method !== 'HEAD';
|
const canHaveBody = method !== 'GET' && method !== 'HEAD';
|
||||||
|
|
||||||
// 3. 处理 Body 和 Content-Type 的核心逻辑
|
|
||||||
if (canHaveBody) {
|
if (canHaveBody) {
|
||||||
if (body instanceof FormData) {
|
if (body instanceof FormData) {
|
||||||
requestBody = body;
|
requestBody = body;
|
||||||
// 【关键修复】如果是 FormData,必须删除 Content-Type,让浏览器自动设置 boundary
|
|
||||||
delete requestHeaders['content-type'];
|
delete requestHeaders['content-type'];
|
||||||
} else if (body) {
|
} else if (body) {
|
||||||
// 如果是普通对象,强制设置为 JSON
|
|
||||||
requestHeaders['content-type'] = 'application/json';
|
requestHeaders['content-type'] = 'application/json';
|
||||||
requestBody = JSON.stringify(body);
|
requestBody = JSON.stringify(body);
|
||||||
}
|
}
|
||||||
@@ -134,7 +124,6 @@ const httpRequest = async <T>(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 4. 更新 API 方法签名,允许 body 为 FormData
|
|
||||||
export const api = {
|
export const api = {
|
||||||
get: <T>(url: string, options?: RequestOptions) =>
|
get: <T>(url: string, options?: RequestOptions) =>
|
||||||
httpRequest<T>(url, 'GET', options),
|
httpRequest<T>(url, 'GET', options),
|
||||||
|
|||||||
Reference in New Issue
Block a user