Lzh on GitHub

Nuxt 请求

Nuxt 请求分为 页面请求和 API请求

在 Nuxt.js 框架中,请求分为 页面请求(服务端渲染相关)和 API 请求(数据获取相关),两者在定位、执行时机和实现方式上有本质差异。以下是核心区别与实现逻辑的全面解析:

一、页面请求(服务端渲染流程)

定位:处理用户访问 URL 时触发的完整页面渲染流程,包含 SSR(服务端渲染)和客户端激活。

流程与关键阶段

  1. 路由解析
  • Nuxt 根据 URL 匹配路由规则,确定渲染的 Vue 组件(如 pages/user/[id].vue)。
  1. 数据预取
  • 执行组件的 asyncDatasetup 中的 useAsyncData/useFetch,在服务端获取初始数据:
    // 示例:页面级数据预取
    export default defineComponent({
      async asyncData({ params }) {
        const user = await $fetch(`/api/users/${params.id}`)
        return { user }
      }
    })
    
  • 数据会序列化到 HTML 的 __NUXT_DATA__ 中,供客户端水合使用。
  1. HTML 生成与注入
  • 服务端渲染 Vue 组件生成 HTML,注入序列化数据,返回给浏览器。
  1. 客户端激活
  • 浏览器加载 HTML 后,Vue 接管 DOM,复用服务端数据激活交互逻辑,避免重复请求。

核心特点

  • SSR 优化:首屏由服务端渲染,提升 SEO 和加载性能。
  • 数据同步:通过 useAsyncData 确保数据在服务端和客户端一致性,避免水合不匹配(Hydration Mismatch)。

二、API 请求(数据获取)

定位:应用内部发起的数据调用,包括访问后端 API 或 Nuxt 自建的 Server API。

实现方式

  1. 内置 $fetch 方法
  • 基于 ofetch 库,全局自动导入,用于简单请求:
    // 客户端事件触发
    async function submitForm() {
      const res = await $fetch('/api/submit', { method: 'POST', body: formData })
    }
    
  • 局限:直接使用可能导致 SSR 重复请求。
  1. 组合式函数封装
  • useFetch:自动处理 SSR 重复请求,将服务端数据注入客户端 payload:
    const { data } = await useFetch('/api/data') // 服务端执行后数据同步到客户端
    
  • useAsyncData:更精细控制,支持自定义键名缓存和刷新:
    const { data } = await useAsyncData('user-data', () => $fetch('/api/user'))
    
  1. Server API 开发
  • Nuxt 自动注册 ~/server/api 目录下的文件为 API 端点:
    // ~/server/api/users/[id].ts
    export default defineEventHandler(event => {
      const id = getRouterParam(event, 'id')
      return { userId: id, name: 'Nuxt User' }
    })
    
  • 支持动态路由、请求方法匹配(get/post 后缀)。

代理配置示例(解决跨域):

// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    devProxy: {
      '/api': { target: 'http://backend:3000', changeOrigin: true }
    }
  }
})

三、核心差异对比

维度页面请求API 请求
触发时机浏览器访问 URL 或路由跳转代码显式调用(如事件、生命周期)
主要技术asyncData, useAsyncData, useFetch$fetch, Server API 端点
数据流服务端获取 → 注入 HTML → 客户端水合直接返回 JSON 或执行后端逻辑
典型场景首屏渲染、SEO 页面表单提交、实时数据更新
性能影响优化首屏加载,减少客户端负担需避免重复请求(SSR 下)

四、最佳实践与避坑指南

  1. 页面请求优化
  • 使用 useAsyncData 替代 asyncData(Nuxt 3 推荐)。
  • 避免在页面请求中混合客户端逻辑,防止水合错误:
    // 错误!客户端代码在服务端执行
    if (process.client) { 
      console.log('仅客户端输出')
    }
    
  1. API 请求封装
  • 服务端专用请求:封装 useServerRequest,通过环境变量区分 baseURL:
    // composables/useServerRequest.ts
    export const useServerRequest = (url, opts) => {
      const baseURL = process.server ? 'http://service-url' : '/api'
      return useFetch(url, { ...opts, baseURL })
    }
    
  • 客户端事件请求:直接用 $fetch,减少序列化开销。
  1. 缓存与性能
  • 利用 useAsyncDatakey 参数实现请求级缓存。
  • 敏感数据避免通过 Server API 暴露(如 __NUXT_DATA__ 中的数据库凭证)。

总结

  • 页面请求是 Nuxt 渲染生命周期的核心,通过 SSR 优化首屏体验,依赖 useAsyncData 保证数据一致性。
  • API 请求分为数据消费($fetch)和提供(Server API),需区分环境处理代理与序列化问题。
  • 混合场景下,优先使用 useFetch 封装通用请求逻辑,结合 Nitro 代理解决跨域,实现高效安全的数据流。