二次封装 fetch
API 是一种常见的做法,特别是在大型项目中,可以统一处理 HTTP 请求和响应。以下是一个使用 TypeScript 进行 fetch
二次封装的完整详细场景使用案例:
1. 创建基础的 fetch 封装
首先,创建一个基础的 fetch
封装,处理基本的 GET 和 POST 请求。
// src/utils/fetch.ts
import { Response, RequestInit } from 'node-fetch';
const BASE_URL = 'https://api.example.com';
async function fetchApi<T>(url: string, options?: RequestInit): Promise<T> {
const response = await fetch(BASE_URL + url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json() as Promise<T>;
}
export async function get<T>(url: string): Promise<T> {
return fetchApi<T>(url, { method: 'GET' });
}
export async function post<T>(url: string, body: any, options?: RequestInit): Promise<T> {
return fetchApi<T>(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), ...options });
}
2. 添加请求拦截器
在发送请求之前,可能需要添加一些通用的处理,如设置认证令牌。
// src/utils/fetch.ts (继续上面的代码)
async function setAuthToken(requestInit: RequestInit): Promise<RequestInit> {
const token = localStorage.getItem('authToken');
if (token) {
requestInit.headers = {
...requestInit.headers,
Authorization: `Bearer ${token}`
};
}
return requestInit;
}
export async function fetchWithAuth<T>(url: string, options?: RequestInit): Promise<T> {
const modifiedOptions = await setAuthToken(options);
return fetchApi<T>(url, modifiedOptions);
}
3. 统一错误处理
统一处理请求错误,使调用者不必在每个请求中处理错误。
// src/utils/fetch.ts (继续上面的代码)
async function fetchApi<T>(url: string, options?: RequestInit): Promise<T> {
try {
const response = await fetch(BASE_URL + url, options);
if (!response.ok) {
const error = new Error(`Fetch error! status: ${response.status}`);
throw error;
}
return response.json() as Promise<T>;
} catch (error) {
console.error('Fetch failed:', error);
throw error;
}
}
4. 使用封装的 fetch 函数
在组件或其他服务中使用封装的 fetch
函数进行请求。
// SomeComponent.vue
import { get, post, fetchWithAuth } from '@/utils/fetch';
export default {
async created() {
try {
const data = await get('/data');
console.log(data);
} catch (error) {
console.error('Failed to fetch data:', error);
}
},
methods: {
async fetchData() {
const newData = await fetchWithAuth('/secure-data');
this.data = newData;
},
async submitForm(formData) {
try {
const result = await post('/submit', formData);
console.log('Form submitted successfully:', result);
} catch (error) {
console.error('Form submission failed:', error);
}
}
}
};
5. 添加请求取消功能
使用 AbortController
来支持请求取消。
// src/utils/fetch.ts (继续上面的代码)
import { AbortController } from 'abortcontroller-polyfill/dist/abortcontroller';
export async function fetchWithCancel<T>(url: string, options?: RequestInit): Promise<T> {
const controller = new AbortController();
const signal = controller.signal;
const fetchPromise = fetchApi<T>(url, { ...options, signal });
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
const response = await fetchPromise;
clearTimeout(timeoutId);
return response;
}
6. 使用请求取消功能
// SomeComponent.vue (继续上面的代码)
methods: {
async fetchDataWithCancel() {
try {
const data = await fetchWithCancel('/data', { method: 'GET' });
console.log(data);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch was cancelled');
} else {
console.error('Fetch failed:', error);
}
}
}
}
通过上述步骤,你可以创建一个功能丰富、灵活且易于使用的 fetch
封装,它包括请求拦截器、统一错误处理、请求取消等功能。这使得在项目中进行 HTTP 请求变得更加一致和方便。