Nuxt 数据获取基础
Nuxt 提供三种数据获取方式,理解它们的区别有助于选择正确的 Movk Nuxt 封装。
$fetch:底层 HTTP 客户端,基于 ofetch,在服务端和客户端均可运行。// 用户点击时调用 -- 适合 $fetch async function handleSubmit() { const result = await $fetch('/api/login', { method: 'POST', body: { username, password } }) }useFetch:useAsyncData+$fetch的语法糖封装// 页面加载时获取数据 -- 适合 useFetch const { data: posts, status, error } = await useFetch('/api/posts')useAsyncData:最灵活的数据获取 composable。// 聚合多个接口 -- 适合 useAsyncData const { data } = await useAsyncData('dashboard', async () => { const [users, stats] = await Promise.all([ $fetch('/api/users'), $fetch('/api/stats') ]) return { users, stats } })
关键参数详解
useFetch(以及 useApiFetch)的三个核心参数决定了请求的执行时机和行为。
server
控制是否在服务端执行数据获取。默认 true。
行为对比:
server: true(默认)-- SSR 时在服务端执行请求,数据通过 payload 传到客户端,客户端不再重复请求server: false-- 仅在客户端执行。首次加载时数据在 hydration 完成后才开始获取,data初始为null
使用场景:
server: true-- SEO 相关数据、首屏需要展示的内容server: false-- 非 SEO 敏感数据(用户评论、个性化推荐、统计数据),减轻服务端负担
// 文章列表需要 SEO -- server: true(默认)
const { data: posts } = await useApiFetch<Post[]>('/posts')
// 评论数据不需要 SSR -- server: false
const { data: comments } = useApiFetch('/comments', {
server: false,
lazy: true,
})
lazy
控制是否阻塞客户端导航。默认 false。
行为对比:
lazy: false(默认)-- 通过 Vue Suspense 阻塞导航,等数据返回后才完成路由切换。用户看不到 loading 状态lazy: true-- 不阻塞导航,页面立即显示,数据在后台获取。需要手动处理 loading 状态
使用场景:
lazy: false-- 页面核心数据,没有数据页面无法正常渲染lazy: true-- 次要数据、非首屏数据、可以先展示骨架屏的场景
// 核心数据 -- 阻塞导航等待数据(默认)
const { data: article } = await useApiFetch<Article>(`/articles/${id}`)
// 次要数据 -- 不阻塞导航,后台加载
const { data: related, status } = useLazyApiFetch<Article[]>(
`/articles/${id}/related`
)
<template>
<!-- 使用 lazy 时需要处理 loading 状态 -->
<div v-if="status === 'pending'">
<USkeleton class="h-20 w-full" />
</div>
<RelatedArticles v-else :articles="related" />
</template>
lazy 的行为与非 lazy 基本一致(都会等待数据返回),差异主要体现在客户端导航时。immediate
控制是否在 composable 初始化时立即执行请求。默认 true。
行为对比:
immediate: true(默认)-- 创建时立即触发请求immediate: false-- 不自动请求,status为idle,需手动调用execute()触发
使用场景:
immediate: true-- 页面加载就需要的数据immediate: false-- 需要等待用户操作后才触发的请求
// 预定义表单提交请求,不自动执行
const { data, execute, status, error } = useApiFetch('/login', {
method: 'POST',
body: credentials,
immediate: false,
lazy: true,
})
// 用户点击登录按钮时手动触发
async function handleLogin() {
await execute()
if (!error.value) {
navigateTo('/dashboard')
}
}
immediate: false 常与 lazy: true 搭配使用。如果只设 immediate: false 而不设 lazy: true,Suspense 仍会等待(虽然请求从未发出),可能导致页面悬挂。Movk Nuxt API 系统
Movk Nuxt 提供基于 $fetch.create() 的 API 客户端工厂($api 插件),以及一组封装 useFetch 的 composable,在 Nuxt 原生数据获取能力之上提供统一的认证、业务检查、Toast 提示等增强功能。
nuxt.config.ts (movk.api 配置)
|
v
api.factory.ts 插件 -- 创建 $api 实例
|
v
拦截器链
├── onRequest: 认证注入 -> debug 日志 -> movk:api:request hook
├── onResponse: 业务检查 -> 数据解包 -> movk:api:response hook -> Toast
└── onResponseError: 401 处理 -> movk:api:error hook -> Toast
|
v
Composables
├── useApiFetch useFetch + $api (SSR/CSR 通用)
├── useLazyApiFetch lazy: true 预设
├── useClientApiFetch server: false, lazy: true 预设
├── useUploadWithProgress XHR 上传 + 进度
└── useDownloadWithProgress fetch + ReadableStream 下载 + 进度
多端点支持
支持配置多个 API 端点,每个端点可独立设置 baseURL、认证、Toast 和响应规则。通过 endpoint 选项或 $api.use() 切换端点。
自动认证
与 nuxt-auth-utils 集成。启用后,每次请求自动从 session 提取 token 并注入到请求头。支持嵌套路径(如 user.accessToken)和多种 token 格式(Bearer、Basic、Custom)。
业务状态码检查
许多后端 API 返回统一格式的响应体:
// HTTP 200,但业务逻辑可能失败
{
code: 400, // 业务状态码
message: '用户名已存在',
data: null
}
$api 拦截器自动检查 code 是否在 successCodes(默认 [200, 0])中。业务失败时抛出 ApiError 并显示 Toast,无需手动处理。
数据解包
$api 拦截器自动提取响应中 dataKey(默认 data)字段的值。useApiFetch<User>('/user') 中泛型 T 直接对应业务数据类型,无需手动 .data.value.data。
// API 原始响应: { code: 200, message: 'OK', data: { id: 1, name: 'test' } }
const { data } = await useApiFetch<User>('/user')
// data.value = { id: 1, name: 'test' } -- 自动解包
若响应中不存在 dataKey 字段,回退返回完整响应对象。
Toast 提示
请求成功/失败时自动显示 Toast 提示。支持四层配置优先级:请求级 > 端点级 > 全局级 > 内置默认值。可在任意层级禁用或自定义。
401 未授权处理
收到 HTTP 401 时,默认自动清除 session 并跳转登录页。可通过 API Hooks 拦截并实现自定义逻辑(如 token 刷新)。