nuxt logo

文档翻译(非官方)

Nuxt.js
Version:v3.17

在 Nuxt 中自定义 useFetch

如何在 Nuxt 中创建一个自定义的 fetcher 来调用外部 API。

在使用 Nuxt 时,你可能会制作前端并获取外部 API,并且你可能希望为从 API 获取数据设置一些默认选项。

$fetch 实用函数(由 useFetch 组合式使用)故意不进行全局配置。这很重要,以便在整个应用程序中保持获取行为的一致性,并且其他集成(如模块)可以依赖于核心实用程序如 $fetch 的行为。

然而,Nuxt 提供了一种方法来为你的 API 创建一个自定义 fetcher(如果你有多个 API 要调用,也可以创建多个 fetcher)。

自定义 $fetch

让我们使用 Nuxt 插件 创建一个自定义的 $fetch 实例。

$fetch 是一个配置过的 ofetch 实例,支持添加 Nuxt 服务器的基本 URL 以及在 SSR 期间直接调用函数(避免 HTTP 往返)。

假设这里:

plugins/api.ts
export default defineNuxtPlugin((nuxtApp) => {
  const { session } = useUserSession()

  const api = $fetch.create({
    baseURL: 'https://api.nuxt.com',
    onRequest({ request, options, error }) {
      if (session.value?.token) {
        // 注意这依赖于 ofetch >= 1.4.0 - 你可能需要刷新你的锁文件
        options.headers.set('Authorization', `Bearer ${session.value?.token}`)
      }
    },
    async onResponseError({ response }) {
      if (response.status === 401) {
        await nuxtApp.runWithContext(() => navigateTo('/login'))
      }
    }
  })

  // 暴露给 useNuxtApp().$api 使用
  return {
    provide: {
      api
    }
  }
})

通过这个 Nuxt 插件,$apiuseNuxtApp() 中暴露出来,以便直接从 Vue 组件中进行 API 调用:

app.vue
const { $api } = useNuxtApp()
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))

使用 useAsyncData 包装 避免在进行服务器端渲染时双重数据获取(服务器和客户端在水合时)。

自定义 useFetch/useAsyncData

现在 $api 已经具备我们想要的逻辑,让我们创建一个 useAPI 组合式来替代 useAsyncData + $api 的使用:

composables/useAPI.ts
import type { UseFetchOptions } from 'nuxt/app'

export function useAPI<T>(
  url: string | (() => string),
  options?: UseFetchOptions<T>,
) {
  return useFetch(url, {
    ...options,
    $fetch: useNuxtApp().$api as typeof $fetch
  })
}

让我们使用新的组合式,创建一个简洁的组件:

app.vue
const { data: modules } = await useAPI('/modules')

如果你想自定义返回的任何错误的类型,你也可以这样做:

import type { FetchError } from 'ofetch'
import type { UseFetchOptions } from 'nuxt/app'

interface CustomError {
  message: string
  statusCode: number
}

export function useAPI<T>(
  url: string | (() => string),
  options?: UseFetchOptions<T>,
) {
  return useFetch<T, FetchError<CustomError>>(url, {
    ...options,
    $fetch: useNuxtApp().$api
  })
}

这个例子展示了如何使用自定义的 useFetch,但相同的结构也适用于自定义的 useAsyncData

我们目前正在讨论找到一种更简洁的方法来让你创建自定义 fetcher,详见 https://github.com/nuxt/nuxt/issues/14736。