---
title: "在 Nuxt 中自定义 useFetch"
description: "如何在 Nuxt 中为调用外部 API 创建自定义的 fetcher。"
canonical_url: "https://nuxt.zhcndoc.com/docs/4.x/guide/recipes/custom-usefetch"
---
# 在 Nuxt 中自定义 useFetch

> 如何在 Nuxt 中为调用外部 API 创建自定义的 fetcher。

当使用 Nuxt 时，你可能在构建前端并从外部 API 获取数据，你可能希望为从你的 API 获取数据设置一些默认选项。

[`$fetch`](https://nuxt.zhcndoc.com/docs/4.x/api/utils/dollarfetch) 工具函数（由 [`useFetch`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-fetch) 组合式函数使用）有意不支持全局配置。这一点很重要，可以确保整个应用中的获取行为保持一致，并让其他集成（如模块）能够依赖 `$fetch` 这样的核心工具函数的行为。

然而，Nuxt 提供了一种方法，允许为你的 API 创建自定义的 fetcher（如果你有多个要调用的 API，也可以创建多个 fetcher）。

## 配方：带认证的 API 客户端

假设你在 `https://api.nuxt.com` 有一个外部 API，它通过 [nuxt-auth-utils](https://github.com/atinux/nuxt-auth-utils) 使用 JWT 认证，并且你希望在收到 `401` 响应时重定向到 `/login`。

```ts [app/composables/useAPI.ts]
export const useAPI = createUseFetch({
  baseURL: 'https://api.nuxt.com',
  onRequest ({ options }) {
    const { session } = useUserSession()
    if (session.value?.token) {
      options.headers.set('Authorization', `Bearer ${session.value.token}`)
    }
  },
  async onResponseError ({ response }) {
    if (response.status === 401) {
      await navigateTo('/login')
    }
  },
})
```

现在，每次调用 `useAPI` 都会自动包含认证请求头并处理 401 重定向：

```vue [app/pages/dashboard.vue]
<script setup lang="ts">
const { data: profile } = await useAPI('/me')
const { data: orders } = await useAPI('/orders')
</script>
```

::read-more{to="https://nuxt.zhcndoc.com/docs/4.x/api/composables/create-use-fetch"}
::

## 配方：自定义 `$fetch` 实例

如果你需要更底层的控制，可以使用 [Nuxt 插件](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/app/plugins)创建一个自定义的 `$fetch` 实例，然后直接与 `useAsyncData` 搭配使用，或将其传递给 `createUseFetch`。

::note
`$fetch` 是 [ofetch](https://github.com/unjs/ofetch) 的一个已配置实例，它支持添加 Nuxt 服务的基础 URL 以及在 SSR 期间直接函数调用（避免 HTTP 往返）。
::

```ts [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) {
        options.headers.set('Authorization', `Bearer ${session.value?.token}`)
      }
    },
    async onResponseError ({ response }) {
      if (response.status === 401) {
        await nuxtApp.runWithContext(() => navigateTo('/login'))
      }
    },
  })

  return {
    provide: {
      api,
    },
  }
})
```

然后你可以直接使用自定义的 `$fetch` 实例：

```vue [app/app.vue]
<script setup>
const { $api } = useNuxtApp()
const { data: modules } = await useAsyncData('modules', () => $api('/modules'))
</script>
```

::callout
使用 [`useAsyncData`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-async-data) 进行包装，可以**避免在服务端渲染期间重复获取数据**（服务端和客户端在 hydration 时）。
::

::link-example{to="https://nuxt.zhcndoc.com/docs/examples/advanced/use-custom-fetch-composable"}
::

::video-accordion{title="观看：Nuxt 中自定义 $fetch 与仓库模式" videoId="jXH8Tr-exhI"}
::


## Sitemap

See the full [sitemap](https://nuxt.zhcndoc.com/sitemap.md) for all pages.
