Nuxt3中用ApiResponse封装useFetch/$fetch响应的方案优化问询
自定义ApiResponse封装useFetch与$fetch的方案优化
一、useFetch中onResponse与transform的执行顺序确认
useFetch的onResponse钩子一定会在transform回调之前执行。
从Nuxt的useFetch实现逻辑来看,它内部调用ofetch完成请求后,会先触发onResponse钩子(此时能拿到完整的Response对象,包含状态码、响应头、原始响应体等),之后才会执行transform回调对响应数据做处理。你查看ofetch源码得到的结论也能印证这一点——ofetch的onResponse是在响应解析(parse)前触发的,而useFetch的transform是基于解析后的数据执行的,所以顺序是确定的。
二、useFetch的封装方案
因为useFetch默认只返回transform处理后的数据,我们可以封装一个自定义的useApiFetch,在onResponse中捕获完整响应信息,再在transform中把这些信息和数据一起封装到ApiResponse类中:
// 自定义封装函数 export function useApiFetch(url, options = {}) { // 用于存储完整响应信息 let responseMeta = null; return useFetch(url, { ...options, onResponse({ response }) { // 先执行用户传入的onResponse(如果有) options.onResponse?.({ response }); // 保存响应元数据:状态码、响应头、原始响应 responseMeta = { status: response.status, statusText: response.statusText, headers: response.headers, }; }, transform(data) { // 执行用户传入的transform(如果有) const transformedData = options.transform?.(data) || data; // 返回封装后的ApiResponse实例 return new ApiResponse(transformedData, responseMeta); }, }); }
调用useApiFetch时,返回的data即为ApiResponse实例,可通过它的方法获取数据、状态码等信息。
三、$fetch的封装优化
如果现有方案存在重复代码或不够简洁,推荐做全局实例化封装:
方案:创建预配置的fetch实例
利用ofetch的createFetch创建一个自带封装逻辑的fetch实例,自动将响应转换为ApiResponse:
import { createFetch } from 'ofetch'; export const apiFetch = createFetch({ baseURL: '/api', // 可根据项目配置基础URL async onResponse({ response }) { // 直接获取ofetch已解析的响应数据 const data = response._data; // 封装为ApiResponse并返回 return new ApiResponse(data, { status: response.status, headers: response.headers, statusText: response.statusText, }); }, });
之后直接调用apiFetch('/endpoint'),返回的就是ApiResponse实例,无需每次手动处理响应。
四、进一步改进建议
- 统一转换逻辑:把ApiResponse的封装逻辑抽成独立函数(如
wrapResponse),让useApiFetch和apiFetch共用,减少代码重复。 - 错误处理整合:在封装中加入统一的HTTP错误捕获,封装为自定义ApiError类,和ApiResponse形成统一返回格式,方便上层处理。
- 类型支持:为ApiResponse和封装函数添加TypeScript类型定义,提升开发体验。
- Nuxt全局注册:如果是Nuxt项目,可在plugins中注册封装后的apiFetch,通过
useNuxtApp().$apiFetch全局调用,更便捷。
内容的提问来源于stack exchange,提问作者Matej
相关产品推荐
相关产品推荐

