我正在开发一个Next.js项目,希望实现tRPC结果的内存缓存,每个tRPC过程都能够 Select 加入一个定制的TTL.我认为tRPC的中间件将适合于此目的.不幸的是,current tRPC middleware documentation似乎不包括这一特定场景.

如何在tRPC 10中实现服务器端缓存中间件?

推荐答案

对于允许轻松实现这一点的功能请求,在Github issue上有一个相关的讨论.同时,仍然可以通过实现定制逻辑来实现这一点.

下面的示例使用node-cache作为内存缓存方法.它已经在tRPC 10.43.3上进行了测试.cachedProcedures中列出的过程被配置为 Select 进入高速缓存.

// src/app/api/middleware/cache.ts

import { initTRPC } from "@trpc/server";
import NodeCache from "node-cache";

const cacheSingleton = new NodeCache();

// A map of cached procedure names to a callable that gives a TTL in seconds
const cachedProcedures: Map<string, (() => number) | undefined> = new Map();
cachedProcedures.set("router0.procedure0", () => 2 * 3600); // 2 hours
cachedProcedures.set("router0.procedure1", () => 1800); // 30 minutes
cachedProcedures.set("router1.procedure0", secondsUntilMidnight); // dynamic TTL
cachedProcedures.set("router1.procedure1", () => undefined); // never expires

const t = initTRPC.create();
const middlewareMarker = "middlewareMarker" as "middlewareMarker" & {
  __brand: "middlewareMarker";
};


const cacheMiddleware = t.middleware(
  async ({ ctx, next, path, type, rawInput }) => {
    if (type !== "query" || !cachedProcedures.has(path)) {
      return next();
    }
    let key = path;
    if (rawInput) {
      key += JSON.stringify(rawInput).replace(/\"/g, "'");
    }
    const cachedData = cacheSingleton.get(key);
    if (cachedData) {
      return {
        ok: true,
        data: cachedData,
        ctx,
        marker: middlewareMarker,
      };
    }
    const result = await next();

    //@ts-ignore
    // data is not defined in the type MiddlewareResult
    const dataCopy = structuredClone(result.data);

    const ttlSecondsCallable = cachedProcedures.get(path);
    if (ttlSecondsCallable) {
      cacheSingleton.set(key, dataCopy, ttlSecondsCallable());
    } else {
      cacheSingleton.set(key, dataCopy);
    }
    return result;
  }
);
export default cacheMiddleware;
// src/server/api, or wherever you define tRPC procedures

import cacheMiddleware from "@/app/api/middleware/cache";
...
export const publicProcedure = t.procedure.use(cacheMiddleware);

以下是几点意见:

  • 该示例假定Next.js应用程序路由,但也应该使用Pages路由或任何其他框架
  • 缓存只对query种类型启用,而不是mutationsubscription
  • 它根据提供给过程的输入使用不同的缓存键
  • middlewareMarker是一个有点老生常谈的修复,因为任何中间件返回必须包括marker
  • structuredClone仅在 node 17+中可用,如果这不是一个选项,则需要不同的深度克隆方法
  • 明智的做法是添加日志(log)记录

Javascript相关问答推荐

Webpack将懒惰加载的模块放入主块中

设置默认值后动态更新japbox或调色板

调用SEARCH函数后,程序不会结束

使用print This时, map 容器已在LeafletJS中初始化

将json数组项转换为js中的扁平

使用AJX发送表单后,$_Post看起来为空

TypScript界面中的Infer React子props

警告!合同执行期间遇到错误[执行已恢复](Base Layer 2)

在React中获取数据后,如何避免不必要的组件闪现1秒?

Msgraph用户邀请自定义邮箱模板

未捕获错误:[]:getActivePinia()被调用,但没有活动Pinia.🍍""在调用app.use(pinia)之前,您是否try 使用store ?""

实现JS代码更改CSS元素

如何控制Reaction路由加载器中的错误状态?

有条件重定向到移动子域

如何利用CSS中的隐藏元素实现平滑扩展和防止网格行间隙

MongoDB受困于太多的数据

传递方法VS泛型对象VS事件特定对象

更新Redux存储中的对象数组

对具有相似属性的对象数组进行分组,并使用串连的值获得结果

Node.js错误: node 不可单击或不是元素