跳至主内容
版本:11.x

响应缓存

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

由于所有 tRPC 查询都是标准的 HTTP GET 请求,因此你可以使用标准的 HTTP 缓存头来缓存响应。这能够显著提升响应速度,减轻数据库压力,并帮助扩展你的 API。

信息

使用缓存时务必谨慎——尤其是在处理个人信息时。

  由于默认启用了批处理,建议在 responseMeta 函数中设置缓存头,并确保没有可能包含个人数据的并发调用——或者,如果存在授权头或 cookie,则应完全省略缓存头。

  你也可以使用 splitLink 将公共请求与那些应保持私有且不缓存的请求分开。

使用 responseMeta 缓存响应

大多数 tRPC 适配器都支持 responseMeta 回调函数,允许你根据被调用的过程设置 HTTP 头(包括缓存头)。

这适用于任何支持标准 HTTP 缓存头的托管服务提供商(例如 Vercel、Cloudflare、AWS CloudFront)。

server.ts
ts
import { initTRPC } from '@trpc/server';
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import type { CreateHTTPContextOptions } from '@trpc/server/adapters/standalone';
 
export const createContext = async (opts: CreateHTTPContextOptions) => {
return {
req: opts.req,
res: opts.res,
};
};
 
type Context = Awaited<ReturnType<typeof createContext>>;
 
export const t = initTRPC.context<Context>().create();
 
const waitFor = async (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));
 
export const appRouter = t.router({
public: t.router({
slowQueryCached: t.procedure.query(async (opts) => {
await waitFor(5000); // wait for 5s
 
return {
lastUpdated: new Date().toJSON(),
};
}),
}),
});
 
// Exporting `type AppRouter` only exposes types that can be used for inference
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export
export type AppRouter = typeof appRouter;
 
// export API handler
const server = createHTTPServer({
router: appRouter,
createContext,
responseMeta(opts) {
const { paths, errors, type } = opts;
// assuming you have all your public routes with the keyword `public` in them
const allPublic = paths && paths.every((path) => path.includes('public'));
// checking that no procedures errored
const allOk = errors.length === 0;
// checking we're doing a query request
const isQuery = type === 'query';
 
if (allPublic && allOk && isQuery) {
// cache request for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
return {
headers: new Headers([
[
'cache-control',
`s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
],
]),
};
}
return {};
},
});
 
server.listen(3000);
server.ts
ts
import { initTRPC } from '@trpc/server';
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import type { CreateHTTPContextOptions } from '@trpc/server/adapters/standalone';
 
export const createContext = async (opts: CreateHTTPContextOptions) => {
return {
req: opts.req,
res: opts.res,
};
};
 
type Context = Awaited<ReturnType<typeof createContext>>;
 
export const t = initTRPC.context<Context>().create();
 
const waitFor = async (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));
 
export const appRouter = t.router({
public: t.router({
slowQueryCached: t.procedure.query(async (opts) => {
await waitFor(5000); // wait for 5s
 
return {
lastUpdated: new Date().toJSON(),
};
}),
}),
});
 
// Exporting `type AppRouter` only exposes types that can be used for inference
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export
export type AppRouter = typeof appRouter;
 
// export API handler
const server = createHTTPServer({
router: appRouter,
createContext,
responseMeta(opts) {
const { paths, errors, type } = opts;
// assuming you have all your public routes with the keyword `public` in them
const allPublic = paths && paths.every((path) => path.includes('public'));
// checking that no procedures errored
const allOk = errors.length === 0;
// checking we're doing a query request
const isQuery = type === 'query';
 
if (allPublic && allOk && isQuery) {
// cache request for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
return {
headers: new Headers([
[
'cache-control',
`s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
],
]),
};
}
return {};
},
});
 
server.listen(3000);
技巧

如果你正在使用 Next.js,请参阅 Next.js SSR 缓存指南,了解使用 createTRPCNext 和 Next.js 适配器的特定于 Next.js 的缓存示例。