Almacenamiento en caché de respuestas
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Los siguientes ejemplos utilizan el almacenamiento en caché de borde de Vercel para servir datos a tus usuarios lo más rápido posible.
⚠️ Una advertencia importante ⚠️
Siempre ten cuidado con el almacenamiento en caché, especialmente cuando manejas información personal.
Dado que el procesamiento por lotes está habilitado por defecto, se recomienda configurar las cabeceras de caché en la función responseMeta y asegurarse de que no haya llamadas concurrentes que puedan incluir datos personales, u omitir completamente las cabeceras de caché si existen cabeceras de autenticación o cookies.
También puedes usar un splitLink para separar tus solicitudes públicas de aquellas que deben ser privadas y no almacenadas en caché.
Almacenamiento en caché de aplicaciones
Si activas SSR en tu aplicación, podrías descubrir que se carga lentamente en plataformas como Vercel, pero en realidad puedes renderizar estáticamente toda tu aplicación sin usar SSG; lee este hilo de Twitter para obtener más información.
Código de ejemplo
pages/_app.tsxtsxexport default withTRPC({config(config) {if (typeof window !== 'undefined') {return {url: '/api/trpc',};}const url = process.env.VERCEL_URL? `https://${process.env.VERCEL_URL}/api/trpc`: 'http://localhost:3000/api/trpc';return {url,};},ssr: true,responseMeta(config) {if (config.clientErrors.length) {// propagate http first error from API callsreturn {status: config.clientErrors[0].data?.httpStatus ?? 500,};}// cache request for 1 day + revalidate once every secondconst ONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers: {'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,},};},})(MyApp);
pages/_app.tsxtsxexport default withTRPC({config(config) {if (typeof window !== 'undefined') {return {url: '/api/trpc',};}const url = process.env.VERCEL_URL? `https://${process.env.VERCEL_URL}/api/trpc`: 'http://localhost:3000/api/trpc';return {url,};},ssr: true,responseMeta(config) {if (config.clientErrors.length) {// propagate http first error from API callsreturn {status: config.clientErrors[0].data?.httpStatus ?? 500,};}// cache request for 1 day + revalidate once every secondconst ONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers: {'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,},};},})(MyApp);
Almacenamiento en caché de respuestas de API
Dado que todas las consultas son HTTP GETs normales, podemos usar cabeceras HTTP estándar para almacenar respuestas en caché, hacer que las respuestas sean rápidas, darle un descanso a tu base de datos y escalar fácilmente tu API para millones de usuarios.
Usar responseMeta para almacenar respuestas en caché
Suponiendo que despliegas tu API en un lugar que pueda manejar cabeceras de caché stale-while-revalidate como Vercel.
server.tstsximport * as trpc from '@trpc/server';import { inferAsyncReturnType } from '@trpc/server';import * as trpcNext from '@trpc/server/adapters/next';export const createContext = async ({req,res,}: trpcNext.CreateNextContextOptions) => {return {req,res,prisma,};};type Context = inferAsyncReturnType<typeof createContext>;export function createRouter() {return trpc.router<Context>();}const waitFor = async (ms: number) =>new Promise((resolve) => setTimeout(resolve, ms));export const appRouter = createRouter().query('public.slow-query-cached', {async resolve({ ctx }) {await waitFor(5000); // wait for 5sreturn {lastUpdated: new Date().toJSON(),};},});// Exporting type _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-exportexport type AppRouter = typeof appRouter;// export API handlerexport default trpcNext.createNextApiHandler({router: appRouter,createContext,responseMeta({ ctx, paths, type, errors }) {// assuming you have all your public routes with the keyword `public` in themconst allPublic = paths && paths.every((path) => path.includes('public'));// checking that no procedures erroredconst allOk = errors.length === 0;// checking we're doing a query requestconst isQuery = type === 'query';if (ctx?.res && allPublic && allOk && isQuery) {// cache request for 1 day + revalidate once every secondconst ONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers: {'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,},};}return {};},});
server.tstsximport * as trpc from '@trpc/server';import { inferAsyncReturnType } from '@trpc/server';import * as trpcNext from '@trpc/server/adapters/next';export const createContext = async ({req,res,}: trpcNext.CreateNextContextOptions) => {return {req,res,prisma,};};type Context = inferAsyncReturnType<typeof createContext>;export function createRouter() {return trpc.router<Context>();}const waitFor = async (ms: number) =>new Promise((resolve) => setTimeout(resolve, ms));export const appRouter = createRouter().query('public.slow-query-cached', {async resolve({ ctx }) {await waitFor(5000); // wait for 5sreturn {lastUpdated: new Date().toJSON(),};},});// Exporting type _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-exportexport type AppRouter = typeof appRouter;// export API handlerexport default trpcNext.createNextApiHandler({router: appRouter,createContext,responseMeta({ ctx, paths, type, errors }) {// assuming you have all your public routes with the keyword `public` in themconst allPublic = paths && paths.every((path) => path.includes('public'));// checking that no procedures erroredconst allOk = errors.length === 0;// checking we're doing a query requestconst isQuery = type === 'query';if (ctx?.res && allPublic && allOk && isQuery) {// cache request for 1 day + revalidate once every secondconst ONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers: {'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,},};}return {};},});