KV 存储

Nitro 提供了一个内置的存储层,可以抽象文件系统、数据库或任何其他数据源。

Nitro 内置了与 unstorage 的集成,以提供一个运行时无关的持久化层。

用法

要使用存储层,你可以使用 useStorage() 工具函数来访问存储实例。

import { useStorage } from "nitro/storage";

// 默认存储(内存中)
await useStorage().setItem("test:foo", { hello: "world" });
const value = await useStorage().getItem("test:foo");

// 你可以使用 useStorage(base) 指定基础前缀
const testStorage = useStorage("test");
await testStorage.setItem("foo", { hello: "world" });
await testStorage.getItem("foo"); // { hello: "world" }

// 你可以使用泛型来指定返回值类型
await useStorage<{ hello: string }>("test").getItem("foo");
await useStorage("test").getItem<{ hello: string }>("foo");
Read more in unstorage.unjs.io.

可用方法

useStorage() 返回的存储实例提供以下方法:

方法描述
getItem(key)获取键的值。如果键不存在则返回 null
getItems(items)一次获取多个项目。接受键数组或 { key, options } 对象。
getItemRaw(key)获取键的原始值,不进行解析。适用于二进制数据。
setItem(key, value)设置键的值。
setItems(items)一次设置多个项目。接受 { key, value } 对象数组。
setItemRaw(key, value)设置键的原始值,不进行序列化。
hasItem(key)检查键是否存在。返回布尔值。
removeItem(key)从存储中移除键。
getKeys(base?)获取所有键,可选按基础前缀过滤。
clear(base?)清除所有键,可选按基础前缀过滤。
getMeta(key)获取键的元数据(例如 mtimeatimettl)。
setMeta(key, meta)设置键的元数据。
removeMeta(key)移除键的元数据。
mount(base, driver)在基础路径动态挂载存储驱动。
unmount(base)从基础路径卸载存储驱动。
watch(callback)监视变更。回调接收 (event, key),其中 event 为 "update""remove"
unwatch()停止监视变更。

还提供了简写别名:getsethasdelremovekeys

import { useStorage } from "nitro/storage";

// 获取前缀下的所有键
const keys = await useStorage("test").getKeys();

// 检查键是否存在
const exists = await useStorage().hasItem("test:foo");

// 移除键
await useStorage().removeItem("test:foo");

// 获取原始二进制数据
const raw = await useStorage().getItemRaw("assets/server:image.png");

// 获取元数据(类型、etag、mtime 等)
const meta = await useStorage("assets/server").getMeta("file.txt");

配置

你可以使用 storage 选项挂载一个或多个自定义存储驱动。

键是挂载点名称,值是驱动名称和配置。

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

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

然后,你可以使用 useStorage("redis") 函数来使用 redis 存储。

你可以在 unstorage 文档 上找到驱动列表及其配置。

开发存储

你可以使用 devStorage 选项在开发和预渲染期间覆盖存储配置。

当你的生产驱动在开发环境中不可用时(例如托管的 Redis 实例),这很有用。

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

export default defineNitroConfig({
  storage: {
    db: {
      driver: "redis",
      host: "prod.example.com",
    }
  },
  devStorage: {
    db: {
      driver: "fs",
      base: "./.data/db"
    }
  }
})

在开发模式下运行时,devStorage 挂载会合并到 storage 挂载之上,允许你在开发时使用本地文件系统驱动或内存驱动。

内置挂载点

Nitro 自动挂载以下存储路径:

/assets

服务器资源挂载在 /assets 基础路径。此挂载点提供对打包服务器资源的只读访问(参见服务器资源)。

import { useStorage } from "nitro/storage";

// 通过 /assets 挂载点访问服务器资源
const content = await useStorage("assets/server").getItem("my-file.txt");

默认(内存中)

根存储(无基础路径)默认使用内存驱动。此处存储的数据在重启后不会持久化。

import { useStorage } from "nitro/storage";

// 默认为内存存储,不会持久化
await useStorage().setItem("counter", 1);

要持久化数据,请使用 storage 配置选项挂载具有持久后端的驱动(例如 fsredis 等)。

服务器资源

Nitro 允许你从项目根目录的 assets/ 目录打包文件。这些文件可以在运行时通过 assets/server 存储挂载点访问。

my-project/
  assets/
    data.json
    templates/
      welcome.html
  server/
    routes/
      index.ts
server/routes/index.ts
import { useStorage } from "nitro/storage";

export default defineHandler(async () => {
  const serverAssets = useStorage("assets/server");

  const keys = await serverAssets.getKeys();
  const data = await serverAssets.getItem("data.json");
  const template = await serverAssets.getItem("templates/welcome.html");

  return { keys, data, template };
});

自定义资源目录

你可以使用 serverAssets 配置选项注册额外的资源目录:

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

export default defineNitroConfig({
  serverAssets: [
    {
      baseName: "templates",
      dir: "./templates",
    }
  ]
})

自定义资源目录可通过 assets/<baseName> 访问:

import { useStorage } from "nitro/storage";

const templates = useStorage("assets/templates");
const keys = await templates.getKeys();
const html = await templates.getItem("email.html");

资源元数据

服务器资源包含元数据,例如内容类型、ETag 和修改时间:

import { useStorage } from "nitro/storage";

const serverAssets = useStorage("assets/server");

const meta = await serverAssets.getMeta("image.png");
// { type: "image/png", etag: "\"...\"", mtime: "2024-01-01T00:00:00.000Z" }

// 适用于设置响应头
const raw = await serverAssets.getItemRaw("image.png");
在开发环境中,服务器资源直接从文件系统读取。在生产环境中,它们会被打包并内联到构建输出中。

运行时配置

在挂载点配置直到运行时才知道的场景中,Nitro 可以使用插件在启动期间动态添加挂载点。

plugins/storage.ts
import { useStorage } from "nitro/storage";
import { definePlugin } from "nitro";
import redisDriver from "unstorage/drivers/redis";

export default definePlugin(() => {
  const storage = useStorage()

  // 从运行时配置或其他来源动态传入凭据
  const driver = redisDriver({
    base: "redis",
    host: process.env.REDIS_HOST,
    port: process.env.REDIS_PORT,
    /* 其他 redis 连接器选项 */
  })

  // 挂载驱动
  storage.mount("redis", driver)
})
这是一个临时解决方案,更好的解决方案将在未来推出!请持续关注 GitHub 上的此议题