数据获取
Nuxt 提供了两个可组合项和一个内置库,用于在浏览器或服务器环境中执行数据获取:useFetch
、useAsyncData
和 $fetch
。
¥Nuxt comes with two composables and a built-in library to perform data-fetching in browser or server environments: useFetch
, useAsyncData
and $fetch
.
简而言之:
¥In a nutshell:
$fetch
是发起网络请求最简单的方式。useFetch
是$fetch
的封装器,在 通用渲染 中仅获取一次数据。useAsyncData
与useFetch
类似,但提供更细粒度的控制。
useFetch
和 useAsyncData
共享一组通用的选项和模式,我们将在最后几节中详细介绍。
¥Both useFetch
and useAsyncData
share a common set of options and patterns that we will detail in the last sections.
useFetch
和 useAsyncData
的必要性
¥The need for useFetch
and useAsyncData
Nuxt 是一个可以在服务器和客户端环境中运行同构(或通用)代码的框架。如果 $fetch
函数 用于在 Vue 组件的 setup 函数中执行数据获取,则可能会导致数据获取两次:一次在服务器端(用于渲染 HTML),另一次在客户端(当 HTML 被 hydrated 时)。这可能会导致混合问题,增加交互时间并导致不可预测的行为。
¥Nuxt is a framework which can run isomorphic (or universal) code in both server and client environments. If the $fetch
function is used to perform data fetching in the setup function of a Vue component, this may cause data to be fetched twice, once on the server (to render the HTML) and once again on the client (when the HTML is hydrated). This can cause hydration issues, increase the time to interactivity and cause unpredictable behavior.
useFetch
和 useAsyncData
可组合项解决了这个问题,它确保如果在服务器上进行 API 调用,数据会通过有效负载转发到客户端。
¥The useFetch
and useAsyncData
composables solve this problem by ensuring that if an API call is made on the server, the data is forwarded to the client in the payload.
有效负载是一个可通过 useNuxtApp().payload
访问的 JavaScript 对象。它在客户端使用,以避免在浏览器 Hydration 期间 中执行代码时重新获取相同的数据。
¥The payload is a JavaScript object accessible through useNuxtApp().payload
. It is used on the client to avoid refetching the same data when the code is executed in the browser during hydration.
<script setup lang="ts">
const { data } = await useFetch('/api/data')
async function handleFormSubmit() {
const res = await $fetch('/api/submit', {
method: 'POST',
body: {
// My form data
}
})
}
</script>
<template>
<div v-if="data == null">
No data
</div>
<div v-else>
<form @submit="handleFormSubmit">
<!-- form input tags -->
</form>
</div>
</template>
在上面的示例中,useFetch
将确保请求在服务器中发生并正确转发到浏览器。$fetch
没有这样的机制,当请求仅从浏览器发出时,$fetch
是更好的选择。
¥In the example above, useFetch
would make sure that the request would occur in the server and is properly forwarded to the browser. $fetch
has no such mechanism and is a better option to use when the request is solely made from the browser.
Suspense
Nuxt 在底层使用 Vue 的 <Suspense>
组件,以防止在所有异步数据可供视图使用之前进行导航。数据获取可组合项可以帮助你利用此功能,并根据每次调用选择最合适的方案。
¥Nuxt uses Vue's <Suspense>
component under the hood to prevent navigation before every async data is available to the view. The data fetching composables can help you leverage this feature and use what suits best on a per-call basis.
<NuxtLoadingIndicator>
以在页面导航之间添加进度条。$fetch
Nuxt 包含 ofetch 库,并会以 $fetch
别名全局自动导入到你的应用中。
¥Nuxt includes the ofetch library, and is auto-imported as the $fetch
alias globally across your application.
<script setup lang="ts">
async function addTodo() {
const todo = await $fetch('/api/todos', {
method: 'POST',
body: {
// My todo data
}
})
}
</script>
$fetch
无法提供 网络调用去重和导航预防。:br 建议使用 $fetch
进行客户端交互(基于事件),或在获取初始组件数据时与 useAsyncData
结合使用。¥Beware that using only $fetch
will not provide network calls de-duplication and navigation prevention. It is recommended to use
$fetch
for client-side interactions (event based) or combined with useAsyncData
when fetching the initial component data.:
了解更多关于 $fetch
的信息。
¥Read more about $fetch
.
::
将客户端标头传递给 API
¥Pass Client Headers to the API
在服务器上调用 useFetch
时,Nuxt 将使用 useRequestFetch
代理客户端标头和 Cookie(不打算转发的标头除外,例如 host
)。
¥When calling useFetch
on the server, Nuxt will use useRequestFetch
to proxy client headers and cookies (with the exception of headers not meant to be forwarded, like host
).
<script setup lang="ts">
const { data } = await useFetch('/api/echo');
</script>
// /api/echo.ts
export default defineEventHandler(event => parseCookies(event))
或者,以下示例展示了如何使用 useRequestHeaders
从服务器端请求(源自客户端)访问并向 API 发送 Cookie。使用同构 $fetch
调用,我们确保 API 端点能够访问用户浏览器最初发送的相同 cookie
标头。仅当你不使用 useFetch
时才需要这样做。
¥Alternatively, the example below shows how to use useRequestHeaders
to access and send cookies to the API from a server-side request (originating on the client). Using an isomorphic $fetch
call, we ensure that the API endpoint has access to the same cookie
header originally sent by the user's browser. This is only necessary if you aren't using useFetch
.
<script setup lang="ts">
const headers = useRequestHeaders(['cookie'])
async function getCurrentUser() {
return await $fetch('/api/me', { headers })
}
</script>
useRequestFetch
自动将标头代理到调用。host
,accept
content-length
,content-md5
,content-type
x-forwarded-host
,x-forwarded-port
,x-forwarded-proto
cf-connecting-ip
,cf-ray
useFetch
useFetch
可组合项在 setup 函数中底层使用 $fetch
进行 SSR 安全的网络调用。
¥The useFetch
composable uses $fetch
under-the-hood to make SSR-safe network calls in the setup function.
<script setup lang="ts">
const { data: count } = await useFetch('/api/count')
</script>
<template>
<p>Page visits: {{ count }}</p>
</template>
此可组合项是对 useAsyncData
可组合项和 $fetch
实用程序的封装器。
¥This composable is a wrapper around the useAsyncData
composable and $fetch
utility.
useAsyncData
useAsyncData
可组合项负责封装异步逻辑并在解析后返回结果。
¥The useAsyncData
composable is responsible for wrapping async logic and returning the result once it is resolved.
useFetch(url)
几乎等同于 useAsyncData(url, () => event.$fetch(url))
。:br 它是针对最常见用例的开发者体验糖。(你可以在 useRequestFetch
上了解更多关于 event.fetch
的信息。)在某些情况下,使用 useFetch
可组合组件并不合适,例如当 CMS 或第三方提供自己的查询层时。在这种情况下,你可以使用 useAsyncData
封装你的调用,同时仍然保留可组合组件提供的优势。
¥There are some cases when using the useFetch
composable is not appropriate, for example when a CMS or a third-party provide their own query layer. In this case, you can use useAsyncData
to wrap your calls and still keep the benefits provided by the composable.
<script setup lang="ts">
const { data, error } = await useAsyncData('users', () => myGetFunction('users'))
// This is also possible:
const { data, error } = await useAsyncData(() => myGetFunction('users'))
</script>
useAsyncData
的第一个参数是一个唯一键,用于缓存第二个参数(查询函数)的响应。可以通过直接传递查询函数来忽略此键,该键将自动生成。 由于自动生成的键仅考虑调用
useAsyncData
的文件和行,因此建议始终创建自己的键以避免出现不必要的行为,例如在创建自定义可组合组件封装 useAsyncData
时。:br 设置键对于在使用
useNuxtData
或 refresh specific data 的组件之间共享相同数据非常有用。<script setup lang="ts">
const { id } = useRoute().params
const { data, error } = await useAsyncData(`user:${id}`, () => {
return myGetFunction('users', { id })
})
</script>
useAsyncData
可组合函数是一种封装并等待多个 $fetch
请求完成,然后处理结果的绝佳方式。
¥The useAsyncData
composable is a great way to wrap and wait for multiple $fetch
requests to be completed, and then process the results.
<script setup lang="ts">
const { data: discounts, status } = await useAsyncData('cart-discount', async () => {
const [coupons, offers] = await Promise.all([
$fetch('/cart/coupons'),
$fetch('/cart/offers')
])
return { coupons, offers }
})
// discounts.value.coupons
// discounts.value.offers
</script>
useAsyncData
用于获取和缓存数据,不会触发副作用(例如调用 Pinia 操作),因为这可能会导致意外行为,例如重复执行并返回空值。如果你需要触发副作用,请使用 callOnce
实用程序。```vue::
:
:read-more{to="/docs/api/composables/use-async-data"}
了解更多关于 `useAsyncData` 的信息。
¥Read more about `useAsyncData`.
::
<a id="return-values"></a>
## 返回值
¥Return Values
`useFetch` 和 `useAsyncData` 具有如下所示的相同返回值。
¥`useFetch` and `useAsyncData` have the same return values listed below.
* `data`:传入的异步函数的结果。
* `refresh`/`execute`:一个函数,用于刷新 `handler` 函数返回的数据。
* `clear`:一个函数,用于将 `data` 设置为 `undefined`,将 `error` 设置为 `null`,将 `status` 设置为 `idle`,并将当前待处理的请求标记为已取消。
* `error`:如果数据获取失败,则返回一个错误对象。
* `status`:一个字符串,指示数据请求的状态(`"idle"`、`"pending"`、`"success"`、`"error"`)。
::note
`data`、`error` 和 `status` 是 Vue 引用,在 `<script setup>` 中使用时可通过 `.value` 访问。
::
默认情况下,Nuxt 会等待 `refresh` 完成后才能再次执行。
¥By default, Nuxt waits until a `refresh` is finished before it can be executed again.
::note
如果你尚未在服务器上获取数据(例如,使用 `server: false`),则在 hydration 完成之前,数据将不会被获取。这意味着,即使你在客户端等待 `useFetch`,`data` 在 `<script setup>` 中仍将保持为 null。
::
<a id="options"></a>
## 选项
¥Options
[`useAsyncData`](/docs/api/composables/use-async-data) 和 [`useFetch`](/docs/api/composables/use-fetch) 返回相同的对象类型,并接受一组通用的选项作为它们的最后一个参数。它们可以帮助你控制可组合项的行为,例如导航阻止、缓存或执行。
¥[`useAsyncData`](/docs/api/composables/use-async-data) and [`useFetch`](/docs/api/composables/use-fetch) return the same object type and accept a common set of options as their last argument. They can help you control the composables behavior, such as navigation blocking, caching or execution.
<a id="lazy"></a>
### 延迟加载
¥Lazy
默认情况下,数据获取可组合项将等待其异步函数解析完毕后,再使用 Vue 的 Suspense 导航到新页面。在使用 `lazy` 选项进行客户端导航时,可以忽略此功能。在这种情况下,你必须使用 `status` 值手动处理加载状态。
¥By default, data fetching composables will wait for the resolution of their asynchronous function before navigating to a new page by using Vue's Suspense. This feature can be ignored on client-side navigation with the `lazy` option. In that case, you will have to manually handle loading state using the `status` value.
```vue twoslash [app.vue]
<script setup lang="ts">
const { status, data: posts } = useFetch('/api/posts', {
lazy: true
})
</script>
<template>
<!-- you will need to handle a loading state -->
<div v-if="status === 'pending'">
Loading ...
</div>
<div v-else>
<div v-for="post in posts">
<!-- do something -->
</div>
</div>
</template>
useLazyFetch
和 useLazyAsyncData
作为便捷的方法来执行相同的操作。¥You can alternatively use useLazyFetch
and useLazyAsyncData
as convenient methods to perform the same.<script setup lang="ts">
const { status, data: posts } = useLazyFetch('/api/posts')
</script>
useLazyFetch
的信息。¥Read more about useLazyFetch
.:::了解更多关于 useLazyAsyncData
的信息。¥Read more about useLazyAsyncData
.::仅客户端抓取
¥Client-only fetching默认情况下,数据获取可组合项将在客户端和服务器环境中执行其异步函数。将server
选项设置为 false
,以便仅在客户端执行调用。初始加载时,数据在 hydration 完成之前不会被获取,因此你必须处理待处理状态。不过,在后续的客户端导航中,数据将被等待加载后再加载页面。¥By default, data fetching composables will perform their asynchronous function on both client and server environments. Set the server
option to false
to only perform the call on the client-side. On initial load, the data will not be fetched before hydration is complete so you have to handle a pending state, though on subsequent client-side navigation the data will be awaited before loading the page.与 lazy
选项结合使用,这对于首次渲染时不需要的数据(例如,非 SEO 敏感数据)非常有用。¥Combined with the lazy
option, this can be useful for data that is not needed on the first render (for example, non-SEO sensitive data)./* This call is performed before hydration */
const articles = await useFetch('/api/article')
/* This call will only be performed on the client */
const { status, data: comments } = useFetch('/api/comments', {
lazy: true,
server: false
})
useFetch
可组合项应在设置方法中调用,或在生命周期钩子函数的顶层直接调用,否则应使用 $fetch
方法。¥The useFetch
composable is meant to be invoked in setup method or called directly at the top level of a function in lifecycle hooks, otherwise you should use $fetch
method.最小化负载大小
¥Minimize payload sizepick
选项可帮助你通过仅选择希望从可组合项返回的字段来最小化存储在 HTML 文档中的有效负载大小。¥The pick
option helps you to minimize the payload size stored in your HTML document by only selecting the fields that you want returned from the composables.<script setup lang="ts">
/* only pick the fields used in your template */
const { data: mountain } = await useFetch('/api/mountains/everest', {
pick: ['title', 'description']
})
</script>
<template>
<h1>{{ mountain.title }}</h1>
<p>{{ mountain.description }}</p>
</template>
transform
函数来更改查询结果。¥If you need more control or map over several objects, you can use the transform
function to alter the result of the query.const { data: mountains } = await useFetch('/api/mountains', {
transform: (mountains) => {
return mountains.map(mountain => ({ title: mountain.title, description: mountain.description }))
}
})
pick
和 transform
均不会阻止初始获取不需要的数据。但它们会阻止将不需要的数据添加到从服务器传输到客户端的有效负载中。缓存和重新获取
¥Caching and refetching键
¥KeysuseFetch
和 useAsyncData
使用键来防止重新获取相同的数据。¥useFetch
and useAsyncData
use keys to prevent refetching the same data.useFetch
使用提供的 URL 作为键。或者,也可以将key
值作为最后一个参数传入options
对象。- 如果
useAsyncData
的第一个参数是字符串,则将其用作键。如果第一个参数是执行查询的处理函数,则会为你生成一个与useAsyncData
实例的文件名和行号唯一的键。
useNuxtData
。共享状态和选项一致性
¥Shared State and Option Consistency当多个组件使用与useAsyncData
或 useFetch
相同的键时,它们将共享相同的 data
、error
和 status
引用。这确保了跨组件的一致性,但需要一些选项保持一致。¥When multiple components use the same key with useAsyncData
or useFetch
, they will share the same data
, error
and status
refs. This ensures consistency across components but requires some options to be consistent.以下选项在使用相同键的所有调用中必须保持一致:¥The following options must be consistent across all calls with the same key:handler
函数deep
选项transform
函数pick
数组getCachedData
函数default
值
// ❌ This will trigger a development warning
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { deep: false })
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { deep: true })
server
lazy
immediate
dedupe
watch
// ✅ This is allowed
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { immediate: true })
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { immediate: false })
// These are completely independent instances
const { data: users1 } = useAsyncData('users-1', () => $fetch('/api/users'))
const { data: users2 } = useAsyncData('users-2', () => $fetch('/api/users'))
响应式键
¥Reactive Keys你可以使用计算引用、普通引用或 getter 函数作为键,从而实现动态数据获取,并在依赖发生变化时自动更新:¥You can use computed refs, plain refs or getter functions as keys, allowing for dynamic data fetching that automatically updates when dependencies change:// Using a computed property as a key
const userId = ref('123')
const { data: user } = useAsyncData(
computed(() => `user-${userId.value}`),
() => fetchUser(userId.value)
)
// When userId changes, the data will be automatically refetched
// and the old data will be cleaned up if no other components use it
userId.value = '456'
刷新并执行
¥Refresh and execute如果你想手动获取或刷新数据,请使用可组合项提供的execute
或 refresh
函数。¥If you want to fetch or refresh data manually, use the execute
or refresh
function provided by the composables.<script setup lang="ts">
const { data, error, execute, refresh } = await useFetch('/api/users')
</script>
<template>
<div>
<p>{{ data }}</p>
<button @click="() => refresh()">Refresh data</button>
</div>
</template>
execute
函数是 refresh
的别名,其工作方式完全相同,但在获取 并非立即发布 时更具语义。¥The execute
function is an alias for refresh
that works in exactly the same way but is more semantic for cases when the fetch is not immediate.clearNuxtData
和 refreshNuxtData
。清除
¥Clear如果你出于某种原因想要清除提供的数据,而不需要知道传递给clearNuxtData
的具体键,你可以使用可组合项提供的 clear
函数。¥If you want to clear the data provided, for whatever reason, without needing to know the specific key to pass to clearNuxtData
, you can use the clear
function provided by the composables.<script setup lang="ts">
const { data, clear } = await useFetch('/api/users')
const route = useRoute()
watch(() => route.path, (path) => {
if (path === '/') clear()
})
</script>
观看
¥Watch要在应用中的其他响应式值每次发生变化时重新运行获取函数,请使用watch
选项。你可以将其用于一个或多个可监视元素。¥To re-run your fetching function each time other reactive values in your application change, use the watch
option. You can use it for one or multiple watchable elements.<script setup lang="ts">
const id = ref(1)
const { data, error, refresh } = await useFetch('/api/users', {
/* Changing the id will trigger a refetch */
watch: [id]
})
</script>
<script setup lang="ts">
const id = ref(1)
const { data, error, refresh } = await useFetch(`/api/users/${id.value}`, {
watch: [id]
})
</script>
计算 URL
¥Computed URL有时你可能需要根据响应式值计算 URL,并在每次更改时刷新数据。你可以将每个参数作为响应式值附加,而无需费力操作。Nuxt 将自动使用响应式值,并在每次更改时重新获取。¥Sometimes you may need to compute an URL from reactive values, and refresh the data each time these change. Instead of juggling your way around, you can attach each param as a reactive value. Nuxt will automatically use the reactive value and re-fetch each time it changes.<script setup lang="ts">
const id = ref(null)
const { data, status } = useLazyFetch('/api/user', {
query: {
user_id: id
}
})
</script>
<script setup lang="ts">
const id = ref(null)
const { data, status } = useLazyFetch(() => `/api/users/${id.value}`, {
immediate: false
})
const pending = computed(() => status.value === 'pending');
</script>
<template>
<div>
<!-- disable the input while fetching -->
<input v-model="id" type="number" :disabled="pending"/>
<div v-if="status === 'idle'">
Type an user ID
</div>
<div v-else-if="pending">
Loading ...
</div>
<div v-else>
{{ data }}
</div>
</div>
</template>
非立即生效
¥Not immediateuseFetch
可组合项将在被调用时开始获取数据。例如,你可以通过设置 immediate: false
来等待用户交互,从而避免这种情况。¥The useFetch
composable will start fetching data the moment is invoked. You may prevent this by setting immediate: false
, for example, to wait for user interaction.这样,你将需要 status
来处理数据获取生命周期,以及 execute
来启动数据获取。¥With that, you will need both the status
to handle the fetch lifecycle, and execute
to start the data fetch.<script setup lang="ts">
const { data, error, execute, status } = await useLazyFetch('/api/comments', {
immediate: false
})
</script>
<template>
<div v-if="status === 'idle'">
<button @click="execute">Get data</button>
</div>
<div v-else-if="status === 'pending'">
Loading comments...
</div>
<div v-else>
{{ data }}
</div>
</template>
status
变量可以是:¥For finer control, the status
variable can be:idle
表示抓取尚未开始pending
表示抓取已开始但尚未完成error
表示抓取失败success
表示抓取成功完成
传递标头和 Cookie
¥Passing Headers and Cookies当我们在浏览器中调用$fetch
时,像 cookie
这样的用户标头将直接发送到 API。¥When we call $fetch
in the browser, user headers like cookie
will be directly sent to the API.通常,在服务器端渲染期间,出于安全考虑,$fetch
不会包含用户的浏览器 Cookie,也不会传递来自 fetch 响应的 Cookie。¥Normally, during server-side-rendering, due to security considerations, the $fetch
wouldn't include the user's browser cookies, nor pass on cookies from the fetch response.然而,当使用服务器上的相对 URL 调用 useFetch
时,Nuxt 将使用 useRequestFetch
来代理 headers 和 cookies(不打算转发的 headers 除外,例如 host
)。¥However, when calling useFetch
with a relative URL on the server, Nuxt will use useRequestFetch
to proxy headers and cookies (with the exception of headers not meant to be forwarded, like host
).在 SSR 响应时从服务器端 API 调用传递 Cookie
¥Pass Cookies From Server-side API Calls on SSR Response如果你想将 cookie 从内部请求传递/代理到客户端,则需要自行处理。¥If you want to pass on/proxy cookies in the other direction, from an internal request back to the client, you will need to handle this yourself.import { appendResponseHeader } from 'h3'
import type { H3Event } from 'h3'
export const fetchWithCookie = async (event: H3Event, url: string) => {
/* Get the response from the server endpoint */
const res = await $fetch.raw(url)
/* Get the cookies from the response */
const cookies = res.headers.getSetCookie()
/* Attach each cookie to our incoming Request */
for (const cookie of cookies) {
appendResponseHeader(event, 'set-cookie', cookie)
}
/* Return the data of the response */
return res._data
}
<script setup lang="ts">
// This composable will automatically pass cookies to the client
const event = useRequestEvent()
const { data: result } = await useAsyncData(() => fetchWithCookie(event!, '/api/with-cookie'))
onMounted(() => console.log(document.cookie))
</script>
选项 API 支持
¥Options API supportNuxt 提供了一种在 Options API 中执行asyncData
抓取的方法。你必须将组件定义封装在 defineNuxtComponent
中才能使其正常工作。¥Nuxt provides a way to perform asyncData
fetching within the Options API. You must wrap your component definition within defineNuxtComponent
for this to work.<script>
export default defineNuxtComponent({
/* Use the fetchKey option to provide a unique key */
fetchKey: 'hello',
async asyncData () {
return {
hello: await $fetch('/api/hello')
}
}
})
</script>
<script setup>
或 <script setup lang="ts">
声明 Vue 组件。从服务器到客户端的序列化数据
¥Serializing Data From Server to Client当使用useAsyncData
和 useLazyAsyncData
将服务器端获取的数据传输到客户端(以及任何其他使用 Nuxt 负载 的组件)时,有效负载将使用 devalue
进行序列化。这不仅使我们能够传输基本的 JSON,还能序列化和恢复/反序列化更高级的数据类型,例如正则表达式、日期、Map 和 Set、ref
、reactive
、shallowRef
、shallowReactive
和 NuxtError
- 以及更多。¥When using useAsyncData
and useLazyAsyncData
to transfer data fetched on server to the client (as well as anything else that utilizes the Nuxt payload), the payload is serialized with devalue
. This allows us to transfer not just basic JSON but also to serialize and revive/deserialize more advanced kinds of data, such as regular expressions, Dates, Map and Set, ref
, reactive
, shallowRef
, shallowReactive
and NuxtError
- and more.对于 Nuxt 不支持的类型,也可以定义自己的序列化器/反序列化器。你可以在 useNuxtApp
文档中阅读更多信息。¥It is also possible to define your own serializer/deserializer for types that are not supported by Nuxt. You can read more in the useNuxtApp
docs.$fetch
或 useFetch
获取时从服务器路由传递的数据 - 请参阅下一节了解更多信息。从 API 序列化数据路由
¥Serializing Data From API Routes从server
目录获取数据时,响应会使用 JSON.stringify
进行序列化。但是,由于序列化仅限于 JavaScript 原始类型,因此 Nuxt 会尽力将 $fetch
和 useFetch
的返回类型转换为与实际值匹配的类型。¥When fetching data from the server
directory, the response is serialized using JSON.stringify
. However, since serialization is limited to only JavaScript primitive types, Nuxt does its best to convert the return type of $fetch
and useFetch
to match the actual value.:JSON.stringify
的限制。¥Learn more about JSON.stringify
limitations.::示例
¥Exampleexport default defineEventHandler(() => {
return new Date()
})
<script setup lang="ts">
// Type of `data` is inferred as string even though we returned a Date object
const { data } = await useFetch('/api/foo')
</script>
自定义序列化函数
¥Custom serializer function要自定义序列化行为,你可以在返回的对象上定义一个toJSON
函数。如果你定义了 toJSON
方法,Nuxt 将遵循该函数的返回类型,并且不会尝试转换类型。¥To customize the serialization behavior, you can define a toJSON
function on your returned object. If you define a toJSON
method, Nuxt will respect the return type of the function and will not try to convert the types.export default defineEventHandler(() => {
const data = {
createdAt: new Date(),
toJSON() {
return {
createdAt: {
year: this.createdAt.getFullYear(),
month: this.createdAt.getMonth(),
day: this.createdAt.getDate(),
},
}
},
}
return data
})
<script setup lang="ts">
// Type of `data` is inferred as
// {
// createdAt: {
// year: number
// month: number
// day: number
// }
// }
const { data } = await useFetch('/api/bar')
</script>
使用替代序列化器
¥Using an alternative serializerNuxt 目前不支持JSON.stringify
的替代序列化器。但是,你可以将有效负载返回为普通字符串,并使用 toJSON
方法来维护类型安全。¥Nuxt does not currently support an alternative serializer to JSON.stringify
. However, you can return your payload as a normal string and utilize the toJSON
method to maintain type safety.在下面的示例中,我们使用 superjson 作为序列化器。¥In the example below, we use superjson as our serializer.import superjson from 'superjson'
export default defineEventHandler(() => {
const data = {
createdAt: new Date(),
// Workaround the type conversion
toJSON() {
return this
}
}
// Serialize the output to string, using superjson
return superjson.stringify(data) as unknown as typeof data
})
<script setup lang="ts">
import superjson from 'superjson'
// `date` is inferred as { createdAt: Date } and you can safely use the Date object methods
const { data } = await useFetch('/api/superjson', {
transform: (value) => {
return superjson.parse(value as unknown as string)
},
})
</script>
Recipes
通过 POST 请求使用 SSE(服务器发送事件)
¥Consuming SSE (Server Sent Events) via POST requestEventSource
或 VueUse 可组合 useEventSource
。// Make a POST request to the SSE endpoint
const response = await $fetch<ReadableStream>('/chats/ask-ai', {
method: 'POST',
body: {
query: "Hello AI, how are you?",
},
responseType: 'stream',
})
// Create a new ReadableStream from the response with TextDecoderStream to get the data as text
const reader = response.pipeThrough(new TextDecoderStream()).getReader()
// Read the chunk of data as we get it
while (true) {
const { value, done } = await reader.read()
if (done)
break
console.log('Received:', value)
}
并行请求
¥Making parallel requests当请求彼此不依赖时,你可以将它们与Promise.all()
并行运行以提高性能。¥When requests don't rely on each other, you can make them in parallel with Promise.all()
to boost performance.const { data } = await useAsyncData(() => {
return Promise.all([
$fetch("/api/comments/"),
$fetch("/api/author/12")
]);
});
const comments = computed(() => data.value?.[0]);
const author = computed(() => data.value?.[1]);