如何在Server Components中优化Fetch请求?最佳实践探讨
Next.js Server Components 中 Fetch 请求的最佳实践
针对你遇到的Server Components中Fetch请求重复代码问题,业内通用的最佳实践是通过封装统一请求工具+模块化API分层来解决,具体实现如下:
1. 封装通用请求工具函数
把baseURL拼接、授权头注入、错误处理这些重复逻辑抽成一个通用函数,比如在/app/utils/api-fetch.ts中:
import { cookies } from 'next/headers'; type ApiFetchOptions = Omit<RequestInit, 'headers'> & { headers?: Record<string, string>; }; export async function apiFetch<T = unknown>( endpoint: string, options: ApiFetchOptions = {} ): Promise<T> { // 获取授权Token const cookieStore = cookies(); const accessToken = cookieStore.get('accessToken')?.value; // 拼接完整API地址 const baseUrl = process.env.NEXT_PUBLIC_API_BASE_URL; const url = `${baseUrl}${endpoint}`; // 合并请求头,优先传入的headers,默认添加授权头 const headers = { 'X-Authorization': accessToken ? `Bearer ${accessToken}` : '', 'Content-Type': 'application/json', ...options.headers, }; const res = await fetch(url, { ...options, headers, // 可选:全局默认缓存策略,业务请求可覆盖 next: { revalidate: 60 }, }); // 统一错误处理,返回更具体的错误信息 if (!res.ok) { const errorData = await res.json().catch(() => null); throw new Error(errorData?.message || `Request failed with status ${res.status}`); } return res.json() as Promise<T>; }
2. 模块化API请求层
将每个业务的API请求单独封装,放在统一的/app/api目录下,便于维护和复用:
/app/api/suite.ts:
import { apiFetch } from '@/app/utils/api-fetch'; import { Suite } from '@/types'; export async function getSuite(propertyId: string, suiteId: string): Promise<Suite> { // 可根据业务需求覆盖缓存策略或请求头 return apiFetch<Suite>(`/suite?propertyId=${propertyId}&suiteId=${suiteId}`); }
/app/api/sensors.ts:
import { apiFetch } from '@/app/utils/api-fetch'; import { Sensor } from '@/types'; export async function getSensorData(deviceId: string): Promise<Sensor[]> { return apiFetch<Sensor[]>(`/sensors?deviceId=${deviceId}`); }
3. Server Components中使用
在Server Components里直接调用封装好的API函数,用Promise.all并行请求提升性能:
import { getSuite } from '@/app/api/suite'; import { getSensorData } from '@/app/api/sensors'; async function ServerComponent() { // 并行请求,避免串行等待 const [suite, sensors] = await Promise.all([ getSuite('property-123', 'suite-456'), getSensorData('device-789'), ]); return ( <div> <h2>Suite: {suite.name}</h2> <div>Sensors count: {sensors.length}</div> </div> ); } export default ServerComponent;
额外优化点
- 类型安全:为API请求定义返回类型,结合TypeScript确保前后端类型一致性
- 缓存定制:业务API函数可通过
apiFetch的next参数覆盖全局缓存策略,比如apiFetch('/suite', { next: { revalidate: 30 } }) - 错误处理:在Server Components中用
try/catch捕获请求错误,返回友好的错误UI - POST请求支持:可在
apiFetch中统一处理body序列化,自动将对象转为JSON字符串
内容的提问来源于stack exchange,提问作者ERTY
相关产品推荐
相关产品推荐

