TypeScript HTTP 客户端:高级请求技术

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

高级 TypeScript HTTP 客户端:从基础请求到工业级解决方案



在开发现代 TypeScript Web 应用程序时,HTTP 请求处理远不止简单的 fetch 调用。在高级层面,不仅需要发送请求,还需要妥善处理错误、管理超时、对响应进行类型化、引入拦截器,甚至缓存数据。在本文中,我们将探讨如何构建一个可靠且灵活的 TypeScript HTTP 客户端,适用于生产级项目。



1. 使用泛型创建类型化 HTTP 客户端



TypeScript 的主要优势之一是强类型化。让我们创建一个基础类 HttpClient,它通过泛型接受响应类型。这有助于在编译阶段避免错误。



// types.tsexport interface ApiResponse<T> {  data: T;  status: number;  ok: boolean;}

export interface RequestConfig { headers?: Record<string, string>; params?: Record<string, string>; signal?: AbortSignal;}

// http-client.tsimport { ApiResponse, RequestConfig } from './types';

class HttpClient { private baseUrl: string;

constructor(baseUrl: string) { this.baseUrl = baseUrl; }

async get<T>(endpoint: string, config?: RequestConfig): Promise<ApiResponse<T>> { const url = new URL(`${this.baseUrl}${endpoint}`); if (config?.params) { Object.entries(config.params).forEach(([key, value]) => { url.searchParams.append(key, value); }); }

const response = await fetch(url.toString(), { method: 'GET', headers: { 'Content-Type': 'application/json', ...config?.headers, }, signal: config?.signal, });

const data: T = await response.json(); return { data, status: response.status, ok: response.ok, }; }

async post<T, U>(endpoint: string, body: U, config?: RequestConfig): Promise<ApiResponse<T>> { const response = await fetch(`${this.baseUrl}${endpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...config?.headers, }, body: JSON.stringify(body), signal: config?.signal, });

const data: T = await response.json(); return { data, status: response.status, ok: response.ok }; }}

export default HttpClient;


2. 错误处理和超时



高级客户端应正确处理网络错误和业务逻辑错误。让我们使用 AbortController 添加超时机制,并进行自定义错误处理。



// errors.tsexport class HttpError extends Error {  status: number;  data?: unknown;

constructor(message: string, status: number, data?: unknown) { super(message); this.name = 'HttpError'; this.status = status; this.data = data; }}

export class TimeoutError extends Error { constructor(timeout: number) { super(`请求在 ${timeout}ms 后超时`); this.name = 'TimeoutError'; }}

// http-client.ts (补充)async requestWithTimeout<T>( endpoint: string, options: RequestInit, timeout: number = 5000): Promise<ApiResponse<T>> { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout);

try { const response = await fetch(`${this.baseUrl}${endpoint}`, { ...options, signal: controller.signal, });

if (!response.ok) { const errorData = await response.json().catch(() => null); throw new HttpError( `HTTP ${response.status}: ${response.statusText}`, response.status, errorData ); }

const data: T = await response.json(); r

博客

书籍推荐