通过 100+ 技巧学习 Nuxt!

Nuxt 中的自定义 useFetch

如何在 Nuxt 3 中创建自定义 fetcher 以调用外部 API。

当使用 Nuxt 时,您可能正在构建前端并获取外部 API,并且您可能想要为从您的 API 获取数据设置一些默认选项。

$fetch 实用函数(由 useFetch composable 使用)被有意地设置为非全局可配置。这很重要,这样在您的整个应用程序中的获取行为保持一致,并且其他集成(如模块)可以依赖于核心实用程序(如 $fetch)的行为。

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

自定义 $fetch

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

$fetchofetch 的已配置实例,它支持添加您的 Nuxt 服务器的基础 URL,以及在 SSR 期间的直接函数调用(避免 HTTP 往返)。

让我们在这里假设

  • 主 API 是 https://api.nuxt.com
  • 我们正在使用 nuxt-auth-utils 将 JWT 令牌存储在会话中
  • 如果 API 响应 401 状态代码,我们将用户重定向到 /login 页面
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) {
        // note that this relies on ofetch >= 1.4.0 - you may need to refresh your lockfile
        options.headers.set('Authorization', `Bearer ${session.value?.token}`)
      }
    },
    async onResponseError({ response }) {
      if (response.status === 401) {
        await nuxtApp.runWithContext(() => navigateTo('/login'))
      }
    }
  })

  // Expose to useNuxtApp().$api
  return {
    provide: {
      api
    }
  }
})

通过此 Nuxt 插件,$apiuseNuxtApp() 中公开,以直接从 Vue 组件进行 API 调用

app.vue
<script setup>
const { $api } = useNuxtApp()
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
</script>
使用 useAsyncData 包装避免在进行服务器端渲染时双重数据获取(服务器和客户端在水合时)。

自定义 useFetch/useAsyncData

现在 $api 具有我们想要的逻辑,让我们创建一个 useAPI composable 来替换 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
  })
}

让我们使用新的 composable 并拥有一个漂亮而干净的组件

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

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

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 是相同的。
观看关于 Nuxt 中自定义 $fetch 和 Repository Pattern 的视频。
我们目前正在讨论寻找一种更简洁的方法让您创建自定义 fetcher,请参阅 https://github.com/nuxt/nuxt/issues/14736