Nuxt3数据请求全解析:如何优雅封装useFetch与$fetch拦截器
在构建现代Web应用时,数据请求是不可或缺的核心功能。Nuxt3作为Vue生态中的全栈框架,提供了useFetch和$fetch两种强大的数据获取方式。本文将深入探讨如何通过拦截器机制实现请求和响应的统一处理,构建可维护性高、复用性强的请求层。
1. Nuxt3数据请求基础解析
Nuxt3内置的数据获取方案相比传统axios有以下优势:
- 开箱即用的SSR支持:自动处理服务端和客户端的数据同步
- 更轻量的依赖:基于ofetch实现,无需额外安装请求库
- 组合式API集成:完美适配Vue3的组合式开发模式
useFetch和$fetch的主要区别:
| 特性 | useFetch | $fetch |
|---|---|---|
| 使用场景 | 组件setup中获取初始数据 | 用户交互触发的请求 |
| 响应式 | 是 | 否 |
| SSR支持 | 自动处理水合 | 需手动处理 |
| 拦截器 | 内置onRequest/onResponse等钩子 | 需自行封装 |
// 基本使用示例 const { data } = await useFetch('/api/users') const response = await $fetch('/api/users')2. 拦截器机制深度剖析
2.1 请求生命周期钩子
Nuxt3的请求拦截器提供了完整的生命周期控制:
const { data } = await useFetch('/api/auth/login', { // 请求发出前 onRequest({ request, options }) { options.headers = { ...options.headers, Authorization: 'Bearer token' } }, // 请求错误时 onRequestError({ error }) { console.error('请求失败:', error) }, // 响应接收后 onResponse({ response }) { if (response.status === 401) { navigateTo('/login') } }, // 响应错误时 onResponseError({ error }) { showError('服务器响应异常') } })2.2 常见拦截场景实现
认证令牌自动注入
function authInterceptor({ options }) { const token = useCookie('token') if (token.value) { options.headers = { ...options.headers, Authorization: `Bearer ${token.value}` } } }API错误统一处理
function errorHandler({ response }) { if (!response.ok) { const errorMap = { 401: '请重新登录', 403: '无权访问', 500: '服务器错误' } throw createError({ statusCode: response.status, message: errorMap[response.status] || '请求失败' }) } }3. 高级封装实践
3.1 工厂函数封装模式
创建可复用的请求工厂:
// composables/useApi.ts export function useApi() { const config = useRuntimeConfig() const baseFetch = (method: string) => async (url: string, opts = {}) => { const baseURL = process.dev ? config.public.API_DEV : config.public.API_PROD return $fetch(url, { baseURL, method, ...opts, onRequest: authInterceptor, onResponse: errorHandler }) } return { get: baseFetch('GET'), post: baseFetch('POST'), put: baseFetch('PUT'), delete: baseFetch('DELETE') } }3.2 类型安全增强
通过泛型实现完善的类型提示:
interface ApiResponse<T> { code: number data: T message?: string } async function typedFetch<T>(url: string): Promise<ApiResponse<T>> { const response = await $fetch(url) return response as ApiResponse<T> } // 使用示例 interface User { id: number name: string } const { data } = await typedFetch<User[]>('/api/users')4. 性能优化与实战技巧
4.1 请求去重与缓存
利用Nuxt3的key机制避免重复请求:
// 相同key的请求会自动去重 const { data } = await useAsyncData('user-data', () => $fetch('/api/user') )4.2 智能重试策略
实现指数退避重试机制:
async function fetchWithRetry(url: string, retries = 3) { let lastError for (let i = 0; i < retries; i++) { try { return await $fetch(url) } catch (err) { lastError = err await new Promise(r => setTimeout(r, 1000 * (i + 1))) } } throw lastError }4.3 请求取消控制
通过AbortController实现请求取消:
const controller = new AbortController() const { data } = await useFetch('/api/data', { signal: controller.signal }) // 需要取消时 controller.abort()在实际项目中,合理的请求层封装可以显著提升开发效率和代码质量。建议根据项目规模选择适当的封装粒度,小型项目可能只需要基础拦截器,而大型项目则可能需要完整的请求工厂和类型系统。