缓存

Nitro 提供了一个基于存储层的缓存系统。
Nitro v3 Alpha 文档仍在开发中——可能会有更新、不完善的地方和偶尔的不准确信息。

缓存处理器

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

它的工作方式类似于 defineHandler,但有一个用于缓存选项的第二个参数。

routes/cached.ts
import { defineCachedHandler } from "nitro/runtime";

export default defineCachedHandler((event) => {
  return "我缓存了一小时";
}, { maxAge: 60 * 60 });

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

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

处理缓存响应时,请求头会被丢弃。使用 varies 选项在缓存和提供响应时考虑特定的头。

缓存函数

你也可以使用 defineCachedFunction 函数缓存一个函数。这对于缓存不是事件处理器但是其中一个部分的函数的结果,并在多个处理器中重用很有用。

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

routes/api/stars/[...repo].ts
import { defineHandler, defineCachedFunction } from "nitro/runtime";

export default defineHandler(async (event) => {
  const { repo } = event.context.params;
  const stars = await cachedGHStars(repo).catch(() => 0)

  return { repo, stars }
});

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

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

在开发中,stars 将被缓存在 .nitro/cache/functions/ghStars/<owner>/<repo>.json 中,value 是 star 的数量。

{"expires":1677851092249,"value":43991,"mtime":1677847492540,"integrity":"ZUHcsxCWEH"}
因为缓存数据被序列化为 JSON,所以重要的是缓存函数不返回任何无法序列化的内容,如 Symbols、Maps、Sets……
如果你使用 edge workers 托管你的应用程序,你应该遵循以下说明。

使用路由规则

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

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

nitro.config.ts
import { defineNitroConfig } from "nitro/config";

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

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

nitro.config.ts
import { defineNitroConfig } from "nitro/config";

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

缓存存储

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

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

nitro.config.ts
import { defineNitroConfig } from "nitro/config";

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

在开发中,你也可以使用 devStorage 选项覆盖缓存挂载点:

nitro.config.ts
import { defineNitroConfig } from "nitro/config";

export default defineNitroConfig({
  storage: {
    cache: {
      // 生产缓存存储
    },
  },
  devStorage: {
    cache: {
      // 开发缓存存储
    }
  }
})

选项

defineCachedHandlerdefineCachedFunction 函数接受以下选项:

base
string
用于缓存的存储挂载点名称。:br 默认为 cache
name
string
如果未提供,则从函数名猜测,否则回退到 '_'
group
string
处理器默认为 'nitro/handlers',函数默认为 'nitro/functions'
getKey()
(...args) => string
一个接受与原始函数相同参数并返回缓存键(String)的函数。:br 如果未提供,将使用内置哈希函数基于函数参数生成键。
integrity
string
一个在更改时使缓存失效的值。:br 默认情况下,它从函数代码计算,用于在开发中在函数代码更改时使缓存失效。
maxAge
number
缓存有效的最大年龄,以秒为单位。:br 默认为 1(秒)。
staleMaxAge
number
陈旧缓存有效的最大年龄,以秒为单位。如果设置为 -1,在后台更新缓存时仍会向客户端发送陈旧的值。:br 默认为 0(禁用)。
swr
boolean
启用 stale-while-revalidate 行为,在异步重新验证时提供陈旧的缓存响应。:br 默认为 true
shouldInvalidateCache()
(..args) => boolean
一个返回 boolean 的函数,用于使当前缓存失效并创建新缓存。
shouldBypassCache()
(..args) => boolean
一个返回 boolean 的函数,用于绕过当前缓存而不使现有条目失效。
varies
string[]
要考虑缓存的一组请求头,了解更多。如果在多租户环境中使用,你可能需要传递 ['host', 'x-forwarded-host'] 以确保这些头不被丢弃,并且缓存对每个租户是唯一的。

缓存键和失效

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

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

例如,以下函数:

import { defineCachedFunction } from "nitro/runtime";

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

将生成以下缓存键:

nitro:functions:getAccessToken:default.json

你可以使用以下方式使缓存函数条目失效:

import { useStorage } from "nitro/runtime";

await useStorage('cache').removeItem('nitro:functions:getAccessToken:default.json')
阅读更多关于 Nitro 存储的信息。