Guide

缓存

Nitro 提供了一个基于存储层的缓存系统。

缓存的事件处理程序

要缓存一个事件处理程序,只需使用 defineCachedEventHandler 方法。

它的工作方式类似于 defineEventHandler,但有一个额外的第二个 options 参数。

routes/cached.ts
// 缓存一个 API 处理程序
export default defineCachedEventHandler((event) => {
  // 我的事件处理程序
}, { maxAge: 60 * 60 /* 1 小时 */ });

在这个例子中,响应将缓存 1 小时,且在缓存更新期间,将向客户端发送一个过期的值。如果你想立即返回更新后的响应,可以将 swr: false 设置为 false。

所有传入请求头在处理缓存响应时会被丢弃。如果你定义了 varies 选项,只有指定的请求头在缓存和提供响应时会被考虑。

有关可用选项的更多详细信息,请参见 options 部分。

你也可以使用 cachedEventHandler 方法作为 defineCachedEventHandler 的别名。

缓存函数

你还可以使用 defineCachedFunction 函数来缓存一个函数。这对于缓存一个不是事件处理程序但又是其中一部分的函数的结果,并在多个处理程序中重用它非常有用。

例如,你可能想要缓存一个 API 调用的结果,持续 1 小时:

export const cachedGHStars = defineCachedFunction(async (repo: string) => {
  const data: any = await $fetch(`https://api.github.com/repos/${repo}`)

  return data.stargazers_count
}, {
  maxAge: 60 * 60,
  name: 'ghStars',
  getKey: (repo: string) => repo
})

星星数量将被缓存到开发环境中的 .nitro/cache/functions/ghStars/<owner>/<repo>.jsonvalue 为星星的数量。

{"expires":1677851092249,"value":43991,"mtime":1677847492540,"integrity":"ZUHcsxCWEH"}
你也可以使用 cachedFunction 方法作为 defineCachedFunction 的别名。

边缘工作者

在边缘工作者中,每个请求后实例会被销毁。Nitro 自动使用 event.waitUntil 来保持实例在缓存更新时的存活,同时将响应发送到客户端。

为了确保你的缓存函数在边缘工作者中按预期工作,你应该始终将 event 作为第一个参数传递给使用 defineCachedFunction 的函数。

import type { H3Event } from 'h3'

export const cachedGHStars = defineCachedFunction(async (event: H3Event, repo: string) => {
  const data: any = await $fetch(`https://api.github.com/repos/${repo}`)

  return data.stargazers_count
}, {
  maxAge: 60 * 60,
  name: 'ghStars',
  getKey: (event: H3Event, repo: string) => repo
})

通过这种方式,函数将能够在缓存更新期间保持实例活着,而不会减慢对客户端的响应。

缓存路由规则

此功能使你可以在主配置文件中以 glob 模式直接添加缓存路由。这对于为应用程序的一部分提供全局缓存策略特别有用。

缓存所有博客路由 1 小时,并具有 stale-while-revalidate 的行为:

export default defineNitroConfig({
  routeRules: {
    "/blog/**": { cache: { maxAge: 60 * 60 } },
  },
});

如果我们想使用一个 自定义存储 挂载点,我们可以使用 base 选项。

export default defineNitroConfig({
  storage: {
    redis: {
      driver: "redis",
      url: "redis://localhost:6379",
    },
  },
  routeRules: {
    "/blog/**": { cache: { maxAge: 60 * 60, base: "redis" } },
  },
});

自定义缓存存储

Nitro 将数据存储在 cache: 挂载点。

要覆盖生产存储,可以使用 storage 选项设置 cache 挂载点:

export default defineNitroConfig({
  storage: {
    cache: {
      driver: 'redis',
      /* redis 连接选项 */
    }
  }
})

在开发中,你还可以使用 devStorage 选项重写缓存挂载点:

export default defineNitroConfig({
  devStorage: {
    cache: {
      driver: 'redis',
      /* redis 连接选项 */
    }
  }
})

选项

cachedEventHandlercachedFunction 函数接受以下选项:

base
string

用于缓存的存储挂载点名称。
默认为 cache

name
string

如果未提供,则根据函数名称推测,且如果后备则为 '_'

group
string

对于处理程序默认为 'nitro/handlers',对于函数默认为 'nitro/functions'

getKey()
(...args) => string

一个接受与原始函数相同参数并返回缓存键(String)的函数。
如果未提供,将使用内置的哈希函数生成基于函数参数的键。

integrity
string

当更改时使缓存失效的值。
默认情况下,它是从 函数代码 计算得出的,用于在函数代码更改时使缓存失效。

maxAge
number

缓存有效的最大时间,单位为秒。
默认为 1(秒)。

staleMaxAge
number

缓存失效的最大时间,单位为秒。如果设置为 -1,则在后台更新缓存时仍会向客户端发送过期值。
默认值为 0(禁用)。

swr
boolean

启用 stale-while-revalidate 行为,以异步重新验证时服务一个过期的缓存响应。
默认值为 true

shouldInvalidateCache()
(..args) => boolean

返回 boolean 的函数,用于使当前缓存失效并创建一个新的缓存。

shouldBypassCache()
(..args) => boolean

返回 boolean 的函数,用于在不使现有条目失效的情况下绕过当前缓存。

varies
string[]

要考虑的请求头数组,了解更多。如果在多租户环境中使用,可能希望传递 ['host', 'x-forwarded-host'],以确保这些头不会被丢弃,并且缓存对于每个租户都是唯一的。

缓存键与失效

使用 defineCachedFunctiondefineCachedEventHandler 函数时,缓存键是使用以下模式生成的:

`${options.group}:${options.name}:${options.getKey(...args)}.json`

例如,以下函数:

const getAccessToken = defineCachedFunction(() => {
  return String(Date.now())
}, {
  maxAge: 10,
  name: 'getAccessToken',
  getKey: () => 'default'
})

将生成以下缓存键:

nitro:functions:getAccessToken:default.json

你可以使用以下代码使缓存函数条目失效:

await useStorage('cache').removeItem('nitro:functions:getAccessToken:default.json')