自定义 useFetch Nuxt
在使用 Nuxt 时,你可能正在构建前端并获取外部 API,并且你可能希望设置一些从 API 中获取数据的默认选项。
¥When working with Nuxt, you might be making the frontend and fetching an external API, and you might want to set some default options for fetching from your API.
$fetch
实用程序函数(由 useFetch
可组合项使用)特意设置为不可全局配置。这很重要,以便在整个应用中的获取行为保持一致,并且其他集成(如模块)可以依赖于核心实用程序(如 $fetch
)的行为。
¥The $fetch
utility function (used by the useFetch
composable) is intentionally not globally configurable. This is important so that fetching behavior throughout your application remains consistent, and other integrations (like modules) can rely on the behavior of core utilities like $fetch
.
但是,Nuxt 提供了一种为你的 API 创建自定义抓取器的方法(如果你要调用多个 API,则可以创建多个抓取器)。
¥However, Nuxt provides a way to create a custom fetcher for your API (or multiple fetchers if you have multiple APIs to call).
$fetch
自定义
¥Custom $fetch
让我们创建一个带有 Nuxt 插件 的自定义 $fetch
实例。
¥Let's create a custom $fetch
instance with a Nuxt plugin.
$fetch
是 ofetch 的一个已配置实例,它支持添加 Nuxt 服务器的基 URL,以及在服务器端渲染 (SSR) 期间直接调用函数(避免 HTTP 往返)。我们假设:
¥Let's pretend here that:
- 主要 API 是 https://api.nuxt.com
- 我们将 JWT 令牌存储在与 nuxt-auth-utils 的会话中。
- 如果 API 响应
401
状态码,我们会将用户重定向到/login
页面。
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 调用:
¥With this Nuxt plugin, $api
is exposed from useNuxtApp()
to make API calls directly from the Vue components:
<script setup>
const { $api } = useNuxtApp()
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
</script>
useAsyncData
封装可避免在进行服务器端渲染(服务器和客户端混合渲染)时重复获取数据。¥Wrapping with useAsyncData
avoid double data fetching when doing server-side rendering (server & client on hydration).useFetch
/useAsyncData
自定义
¥Custom useFetch
/useAsyncData
既然 $api
已经具备了我们想要的逻辑,让我们创建一个 useAPI
可组合组件来替换 useAsyncData
+ $api
的用法:
¥Now that $api
has the logic we want, let's create a useAPI
composable to replace the usage of useAsyncData
+ $api
:
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
})
}
让我们使用新的可组合项,创建一个简洁美观的组件:
¥Let's use the new composable and have a nice and clean component:
<script setup>
const { data: modules } = await useAPI('/modules')
</script>
如果你想自定义返回的错误类型,也可以这样做:
¥If you want to customize the type of any error returned, you can also do so:
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
的结构相同。