在 Nuxt 中自定义 useFetch
如何在 Nuxt 中为调用外部 API 创建自定义的 fetcher。
当使用 Nuxt 时,你可能在构建前端并从外部 API 获取数据,你可能希望为从你的 API 获取数据设置一些默认选项。
$fetch
工具函数(由 useFetch
组合式函数使用)是刻意不可全局配置的。这一点很重要,以便应用中各处的获取行为保持一致,并且其他集成(如模块)可以依赖核心工具(如 $fetch
)的行为。
然而,Nuxt 提供了一种方法,允许为你的 API 创建自定义的 fetcher(如果你有多个要调用的 API,也可以创建多个 fetcher)。
$fetch
自定义
让我们使用一个 Nuxt 插件 来创建一个自定义的 $fetch
实例。
$fetch
是 ofetch 的一个已配置实例,它支持添加 Nuxt 服务的基础 URL 以及在 SSR 期间直接函数调用(避免 HTTP 往返)。我们这里假设:
- 主 API 是 https://api.nuxt.com
- 我们使用 nuxt-auth-utils 将 JWT 令牌存储在会话中
- 如果 API 返回
401
状态码,我们会将用户重定向到/login
页面
app/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 插件,$api
会从 useNuxtApp()
暴露出来,以便在 Vue 组件中直接进行 API 调用:
app/app.vue
<script setup>
const { $api } = useNuxtApp()
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
</script>
使用
useAsyncData
包装可以避免在进行服务器端渲染时产生重复的数据获取(服务器端与客户端在 hydration 时)。useFetch
/useAsyncData
自定义
既然 $api
已经包含了我们需要的逻辑,让我们创建一个 useAPI
组合式函数来替换 useAsyncData
+ $api
的用法:
app/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/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
,结构是完全相同的。 Read and edit a live example in Docs > 4 X > Examples > Advanced > Use Custom Fetch Composable.
我们目前正在讨论找到一种更简洁的方法让你创建自定义 fetcher,详见 https://github.com/nuxt/nuxt/issues/14736。