Guide

缓存

Nitro 提供了一种构建在存储层之上的缓存系统。

缓存的事件处理器

要缓存事件处理器,您只需使用 defineCachedEventHandler 方法。

它的工作方式与 defineEventHandler 相似,但增加了第二个 options 参数。

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

在此示例中,响应将在 1 小时内被缓存,同时在后台更新缓存时,将发送一个过期值到客户端。如果您希望立即返回更新后的响应,请设置 swr: 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>.json 中,value 是星星的数量。

{"expires":1677851092249,"value":43991,"mtime":1677847492540,"integrity":"ZUHcsxCWEH"}

::important 由于缓存数据被序列化为 JSON,因此重要的是缓存的函数不能返回任何不能序列化的内容,例如 Symbols、Maps、Sets 等。 ::

您也可以使用 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
})

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

缓存路由规则

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

使用 stale-while-revalidate 行为缓存所有博客路由 1 小时:

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')