Agent Developer Roadmap
前端框架

Nuxt:useAsyncData、Nitro 与混合渲染

最后核验:2026-06-30|适用版本:Nuxt 2–4(示例锁定 4.4.8)|前置知识:Vue、HTTP、Node.js

Nuxt 的约定式能力边界

Nuxt 在 Vue 之上提供文件路由、服务端渲染、数据载荷、自动导入、Nitro 服务端和部署 preset。需要 Vue 全栈渲染与统一服务端入口时,这些约定减少手工组合;纯客户端局部组件不需要为了自动导入承担服务端和部署模型。

Nuxt 4 使用 app/ 目录隔离应用代码,并用独立 TypeScript 项目区分 app、server、shared 和配置上下文。自动导入减少样板,但读代码时仍要知道 API 来自 Vue、Nuxt 还是 Nitro。

文件路由与服务端首屏

app/pages 形成路由,app/layouts 提供布局,server/api 进入 Nitro。初次请求在服务端执行页面 setup,生成 HTML 和数据载荷;客户端用相同载荷水合,导航时再通过 Vue Router 和 Nuxt 数据协议更新。

服务端和客户端首屏必须得到确定一致的输入。浏览器 API 放进 onMounted 或客户端插件;时间、随机数和设备状态不能直接改变首屏模板。

目录约定如何组成应用

Nuxt 4 默认把浏览器应用放进 app/pages/ 生成 Vue Router 路由,layouts/ 包住页面,components/ 可自动导入组件,composables/utils/ 提供自动导入逻辑,plugins/ 扩展 Nuxt/Vue 实例,middleware/ 执行路由导航检查。server/ 属于 Nitro 服务端,shared/ 才是可同时被两侧安全引用的无环境依赖代码。

app/
├── app.vue
├── layouts/default.vue
├── pages/
│   ├── index.vue
│   └── entries/[id].vue
├── middleware/auth.ts
└── plugins/analytics.client.ts
server/
├── api/entries/[id].get.ts
└── middleware/request-id.ts
shared/
└── types/entry.ts

<NuxtPage> 承载当前页面,<NuxtLayout> 选择布局。页面可用 definePageMeta 声明 layout、middleware、key 和自定义元数据;动态参数从 useRoute().params 读取并做运行时校验。页面 key 决定何时复用组件实例,错误地绑定整个 fullPath 会让 query 每变一次就销毁所有局部状态。

路由 middleware 在初次 SSR 和客户端导航都可能运行,适合重定向与导航体验;它不是数据授权层。Nitro server middleware 则处理每个匹配的服务端请求,不能混用 useRoute 等客户端上下文。插件用 .client.server 后缀限制执行环境;无后缀插件在 SSR 与浏览器各执行一次,注册全局监听器或发埋点时必须避免双重副作用。

首个 HTML 请求的执行顺序大致是 Nitro 接收请求、匹配路由、建立 Nuxt app、运行插件/middleware、执行页面 setup 与数据 composable、渲染 Vue HTML、序列化 payload。浏览器创建新的 Nuxt app,读取 payload 后水合,再进入正常 Vue Router 导航。模块全局变量不会自动成为“请求级状态”,在长驻 Node 进程中会跨用户共享;请求状态应放 useState、event context 或每次创建的实例中。

useAsyncData 的键、载荷与去重

useAsyncData(key, handler) 管理异步数据、错误、状态、载荷传输和重新执行。键决定同一请求和水合过程中的共享身份;同键的 handler 和关键选项必须兼容。handler 应有确定返回值,服务端副作用使用 callOnce 或明确的服务器接口。

<script setup lang="ts">
const { data, error, status, refresh } = await useAsyncData(
  'technology-catalog',
  () => $fetch('/api/catalog'),
);
</script>

无键调用可以由编译器生成位置键,但公共组合函数应显式命名,便于诊断缓存和重复请求。refresh 重新执行当前数据源,不等于清除所有 Nitro 或 CDN 缓存。

useAsyncData 返回的 dataerrorstatus 是 Vue ref。handler 在 SSR 成功返回的值会进入 Nuxt payload,客户端水合时读取而不重复调用;若 handler 返回 undefined/null 或值无法正确序列化,客户端可能再次执行。handler 应保持无副作用、返回明确值,数据库写入、cookie 修改和埋点不要藏在里面。

export function useCatalog(locale: Ref<string>) {
  return useAsyncData(
    () => `catalog:${locale.value}`,
    (_nuxtApp, { signal }) =>
      $fetch('/api/catalog', {
        query: { locale: locale.value },
        signal,
      }).then(parseCatalog),
    {
      watch: [locale],
      deep: false,
      dedupe: 'cancel',
      default: () => [],
    },
  );
}

key 是跨 SSR、payload、水合和同页消费者的身份。相同 key 的 handler、deeptransformpickgetCachedData 等关键选项必须一致,否则两个组件以为共享同一数据,实际对结果形状和刷新规则理解不同。把 locale、tenant、排序或权限等影响结果的维度漏出 key,会复用错误内容;把时间戳放 key 又会消灭去重并无限增长 payload。

lazy: false 的数据默认参与导航等待;lazy: true 允许先导航再展示 pending,useLazyAsyncData 是相同意图的便捷形式。server: false 会让首个 SSR 不执行 handler,水合完成前 data 仍为空,适合纯浏览器能力但会牺牲首屏内容。immediate: false 需要手工 execute,不应假设 await composable 后已有值。

deep: true 为结果创建深层响应式,庞大只读响应可用 deep: false 减少代理成本;picktransform 在进入 payload 前裁剪字段。裁剪是传输/性能决策,不是权限措施:无权数据根本不应从服务端查询或交给 handler。

refresh() 遵循当前 key 和 handler 重新获取,clear() 清掉当前 AsyncData 状态,refreshNuxtData(key) 可刷新匹配 key 的数据。它们不会自动清除 Nitro cached event handler、反向代理或浏览器 HTTP cache。调试重复请求时记录 key、SSR/CSR 环境、payload 是否命中和实际网络层,不能只数 handler 日志。

useFetch 与请求取消

useFetch 是针对 URL 请求的 useAsyncData 包装,自动生成键并使用 $fetch。响应仍是不可信输入,进入组件前要运行时验证。Nuxt 4.2 支持把 AbortSignal 传给 useAsyncData/useFetch 的请求;取消属于生命周期控制,不应显示成网络故障。Nuxt 4.2

情况首选原因
直接请求 URLuseFetch键与请求选项集成
多步骤或非 HTTP 异步useAsyncDatahandler 自定义
仅客户端事件请求$fetch不需要 SSR payload
服务端内部 API直接调用共享函数避免无意义自请求

不要在服务端渲染中用裸 $fetch 后又在客户端重复执行同一请求;需要载荷复用时使用 useAsyncDatauseFetch

$fetch 基于 ofetch,适合事件触发的命令请求和 Nitro handler 内部调用。服务端 $fetch('/api/catalog') 可通过 Nitro 本地调用避免真实网络回环,但仍经过 handler 信任边界;若页面和 handler 属于同一部署且共享领域函数,直接调用服务层更容易传递类型、事务和取消。

useFetch 的 URL、query、headers 等可以是响应式来源;变化会触发重新请求并影响自动 key。不要内联每次都创建且语义变化的复杂对象,公共封装应使用稳定 option 并显式 key。请求取消只保证客户端不再等待/处理结果,服务端已开始的写操作未必回滚,因此 GET 可取消,POST 写入仍需幂等与事务。

浏览器调用同源 Nitro API 时 cookie 自然随请求策略发送;SSR 中转外部或上游 cookie/headers 必须使用受控白名单,不能把用户全部请求头转发到任意 URL。useRequestFetch 可携带请求上下文,但敏感 header、host 与 forwarded 信息仍需按可信代理配置处理。

Nitro 请求与部署边界

Nitro 处理 server/api、middleware、存储和不同平台输出。服务端 handler 使用 H3 事件读取参数、请求体和上下文,信任边界在这里执行认证、授权与运行时验证。runtimeConfig 的私有字段只留服务端,public 字段会进入客户端载荷。

Nitro preset 决定产物适配 Node、serverless、edge 或静态托管。运行时 API、文件系统、连接复用和缓存能力随部署环境变化;先选择目标环境,再决定是否使用 Node 专属模块。

Nitro/H3 handler 以文件名方法后缀和目录生成路由,例如 server/api/entries/[id].patch.ts 只处理 PATCH。事件对象承载 request、params、context 和 response;读取 body、query、cookie 后都要解析为领域值。TypeScript 的泛型只约束编译期调用方,不能证明公网请求符合类型。

export default defineEventHandler(async (event) => {
  const user = await requireUser(event);
  const id = getRouterParam(event, 'id') ?? '';
  const body = await readValidatedBody(event, updateEntrySchema.parse);

  if (!/^[a-z0-9-]+$/.test(id)) {
    throw createError({ statusCode: 400, statusMessage: 'Invalid entry id' });
  }

  const entry = await updateOwnedEntry({
    id,
    ownerId: user.id,
    title: body.title,
  });

  if (!entry) {
    throw createError({ statusCode: 404, statusMessage: 'Entry not found' });
  }

  return { entry };
});

服务端插件适合建立数据库、日志和 storage driver,event context 适合请求 ID 与认证结果。数据库连接池可以进程级复用,当前用户不可以。serverless 可能并发创建多个实例,edge 可能没有 Node fs、TCP 或某些原生依赖;本地 Node preset 成功只证明一种运行时。

Nitro storage 提供统一键值接口,cachedEventHandler/defineCachedFunction 可缓存响应或函数结果。缓存键必须包含 tenant、locale、权限和所有响应变化维度;私有响应默认不缓存。对 cookie、Authorization、Host 或 body 敏感的 handler,除非明确实现安全 vary,否则不要套公开缓存。多实例部署还要确认 driver 是本地内存、共享 Redis/KV 还是平台缓存,以及失效是否传播。

runtimeConfig 私有值只应在服务器 useRuntimeConfig(event) 读取;runtimeConfig.public 会序列化到客户端。环境变量覆盖遵循 Nuxt 的命名规则,构建期把秘密写入 public 或 payload 后,运行时换变量无法撤回泄露。错误日志同样要删除 Authorization、cookie、token 和未裁剪请求体。

混合渲染与 Route Rules

Nuxt 可按路由选择服务端渲染、预渲染、客户端渲染和缓存规则。Route Rules 是 URL 级策略,适合内容页与应用页共存;错误规则可能把用户数据缓存为公开响应。

缓存必须记录作用域、键、TTL 和失效。开发模式通常不展示完整生产缓存行为,必须用生产构建和目标 preset 验证响应头、命中与过期。

Nuxt 渲染模式是按路由组合的,不是全站四选一:

模式产生时机适合关键限制
SSR每次请求在服务器渲染个性化且需首屏 HTML服务端容量、请求隔离、数据延迟
Prerender/SSG构建或爬取时生成版本化内容和文档构建后数据陈旧,动态路径需枚举/发现
CSR (ssr: false)浏览器下载 JS 后渲染内部工具、强浏览器依赖空壳首屏、SEO/弱网和水合收益丢失
混合 routeRules每条路由选择 prerender、swr、redirect 等内容站与登录应用共仓规则匹配、缓存身份和平台实现复杂
export default defineNuxtConfig({
  routeRules: {
    '/': { prerender: true },
    '/docs/**': { swr: 3600 },
    '/dashboard/**': { ssr: true },
    '/legacy': { redirect: '/docs' },
  },
});

prerender 把当时输出固化为文件;swr 可先服务缓存响应再后台再生;具体是否有分布式持久缓存、如何处理并发再生和失效取决于 Nitro preset/平台。用户 dashboard 不能仅因 URL 看起来稳定就启用 SWR。规则通配、大小写、编码和尾斜杠要在部署产物上测试,尤其不能让 route middleware 成为唯一权限防线。

Nuxt Islands/服务端组件可以只渲染局部服务端内容并减少客户端 JavaScript,但请求绑定、props 序列化和缓存会新增协议面。默认组件已足够时不要为了“零 JS”拆 island;采用后需验证其 endpoint 不可跨会话读取数据,传给客户端的 props 不含秘密,交互组件的水合顺序确定。

水合、payload 与状态恢复

Nuxt payload 保存 SSR 期间 AsyncData、useState 等可序列化状态,客户端据此复用结果。它是 HTML/外部 payload 中可被用户读取的数据,不是服务器私有内存。类实例、函数、数据库句柄和秘密不能进入;复杂类型是否能经 payload reducer/reviver 恢复必须有明确契约。

水合不一致常见于 new Date()Math.random()、服务端/客户端 locale 不同、无效 HTML 被浏览器修正、客户端插件提前改 DOM,以及用模块变量生成 ID。修复要让首帧输入确定,或用 <ClientOnly>/onMounted 把浏览器专属部分明确推迟;不能用宽泛 suppression 隐藏整个页面差异。

useState(key, init) 创建 SSR 友好的共享 ref,并把值放进 payload。key 仍需唯一,init 应纯且请求隔离。Pinia 等 store 也必须按请求创建并安全序列化,不能在模块顶层导出带当前用户数据的单例。

错误处理、性能和可观测性

页面可用 createError/showError 进入 Nuxt 错误页,Nitro handler 应抛带明确 statusCode 的 H3 error。404、401/403、校验失败和 500 是不同契约;可恢复的表单错误留在页面,未知异常记录内部 request ID 后返回稳定消息。clearError({ redirect }) 会清理全局错误并导航,不等于修复失败数据源。

性能问题跨越 Nitro、Vue、payload 和浏览器:

  1. 用服务端 trace 找 API/数据库瀑布,独立请求并发启动;用 payload 面板检查重复或过大字段。
  2. useAsyncData 设计稳定 key,以 pick/transform/deep: false 控制传输与代理成本。
  3. 只缓存可共享且容忍陈旧的数据,记录命中率、再生延迟和源站失败行为。
  4. 路由级代码分割和组件惰性加载要以产物验证;自动导入不会自动消除所有第三方副作用。
  5. 用 Vue Devtools/Performance 查重复 watcher、长任务、布局抖动;SSR 快不代表水合和交互快。

建议为每次请求生成 request ID,贯穿 Nitro 日志、上游请求和错误页 digest;日志标注 SSR/CSR、route、AsyncData key、cache status 和部署 region。开发 DevTools 能解释本机执行,但 serverless 冷启动、edge 限制、CDN cache 和多实例失效只能在目标 preset/预发布环境证明。

知识目录示例的运行证据

Nuxt 示例在服务端 setup 中导入并验证共享目录,首屏包含八项内容;客户端 ref 保存查询和选择,computed 派生结果,watch 只同步路由 query。

运行效果Nuxt 知识目录运行效果
新窗口打开

正在加载示例……

pnpm --filter @roadmap/nuxt-slice test
pnpm --filter @roadmap/nuxt-slice preview --port 4206

输入:访问 http://127.0.0.1:4206/,检查源代码,搜索 nitro,选择两项后刷新。

预期结果:模型测试与 Nitro 生产构建通过;服务端首屏含目录,浏览器控制台无水合警告,URL 恢复查询与选择。示例数据是随部署发布的本地事实,不引入 API 自请求或缓存层。

Nuxt DevTools 与错误定位

Nuxt DevTools 检查路由、payload、组件和模块;服务端终端检查 Nitro;浏览器 Network 区分 HTML、payload 与 API。出现重复请求时先比较 key 和执行环境,出现水合错误时比较服务端 HTML 与客户端首次 setup 输入。

模板默认转义文本,v-html 绕过边界;服务端密钥不能进入 runtimeConfig.public、payload 或错误消息。错误页应区分 404、权限和服务器故障,不把内部堆栈发给浏览器。Nuxt Security

重大重构、路由绕过与 Nuxt 2 到 4 迁移

Nuxt 2 到 3 是完整运行时重构:Vue 2/webpack/传统 serverMiddleware 转为 Vue 3、Vite、Nitro、Composition API 和跨平台产物;Nuxt 4 再把应用移入 app/,分离 app/server/shared TypeScript 上下文,并收紧数据获取一致性。迁移不能只移动目录,必须逐一验证插件执行环境、模块兼容、payload 序列化、runtimeConfig 可见性和 Nitro preset。

节点重大变化易出严重故障的边界
2 → 3Vue 3 + Nitro + Composition API + 新模块体系旧插件全局副作用、serverMiddleware、Vuex/axios 模块和 SSR 差异
3 → 4app/ 目录、数据获取清理、独立 TS 项目自动导入来源、相对路径、同 key handler 与 payload 变化
4.2–4.4AbortSignal、smarter payload、vue-router v5、可访问性 announcer取消被误报、导航/route rules 匹配、缓存 payload 不一致

2026-06 的 CVE-2026-53721(GHSA-mm7m-92g8-7m47)是高危 route-rule middleware 绕过:vue-router 默认大小写不敏感,而 routeRules matcher 大小写敏感,攻击者改变 /admin 静态段大小写后,页面仍匹配但 routeRules.appMiddleware 未执行,SSR 甚至会返回受保护的 useFetch/useAsyncData 数据。Nuxt 4.0.0–4.4.6 与 3.11.0–3.21.6 受影响,修复为 4.4.7/3.21.7;本示例锁定 4.4.8。Nuxt 路由绕过公告

根因修正不止升级:route middleware 从来不应是服务端数据的唯一授权边界。每个 Nitro handler、外部 API 和 SSR 数据入口都重新认证授权;回归同时请求原始、大小写变体、编码变体和尾斜杠路径。同期公告还涉及 navigateTo/NuxtLink 危险协议、开发服务器暴露和 island 请求绑定,生产依赖应按官方 advisory 列表保持最新 patch,并限制外部 URL 协议。Nuxt Security Advisories

Nuxt 2 基于 Vue 2 与旧模块体系;Nuxt 3 引入 Vue 3、Nitro 与 Composition API;Nuxt 4 稳定 app/ 结构、改进数据获取一致性和 TypeScript 项目隔离。当前 v4 是 active,v3 维护至 2026-07-31;升级先启用兼容模式,再处理目录和数据获取差异。Nuxt Roadmap

验收标准:能解释 useAsyncData key、payload 与重新获取;能区分 Nuxt app 和 Nitro server;能为每条 Route Rule 写出缓存与部署前提。

Nuxt 官方资料

  • Nuxt Data FetchinguseAsyncDatauseFetch 与 payload;核验于 2026-06-30。
  • Nuxt Server:Nitro API 与 middleware;核验于 2026-06-30。
  • Nuxt Rendering Modes:SSR、CSR、预渲染和混合规则;核验于 2026-06-30。
  • Nuxt 4 Release:目录、数据获取和类型变化;核验于 2026-06-30。
在 GitHub 上编辑此页

本页目录