Lzh on GitHub

缓存

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

缓存事件处理程序

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

它的工作方式与 defineEventHandler 类似,但多了一个额外的 options 参数。

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

在这个例子中,响应将被缓存 1 小时,并且在后台更新缓存时,会将旧值发送给客户端。如果您想立即返回更新后的响应,请设置 swr: false

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

请参阅 选项 部分,了解有关可用选项的更多详细信息。

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

缓存函数

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

例如,您可能希望缓存 API 调用结果一小时:

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"}
由于缓存的数据被序列化为 JSON,因此缓存函数不应返回任何无法序列化的内容,例如 Symbols、Maps、Sets 等。
您也可以使用 cachedFunction 方法作为 defineCachedFunction 的别名。

Edge Workers

在 Edge Workers 中,实例在每次请求后都会被销毁。Nitro 会自动使用 event.waitUntil 来保持实例的活跃,同时在响应发送给客户端时更新缓存。

为确保您的缓存函数在 Edge Workers 中按预期工作,您应该始终将 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
})

这样,函数将能够在更新缓存的同时保持实例的活跃,而不会降低对客户端的响应速度。

缓存路由规则

此功能允许您直接在主配置文件中根据全局模式添加缓存路由。这对于为应用程序的一部分设置全局缓存策略特别有用。

缓存所有博客路由 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')