Hoppa till huvudinnehållet
Version: 9.x

Cachning av svar

Inofficiell Beta-översättning

Denna sida har översatts av PageTurner AI (beta). Inte officiellt godkänd av projektet. Hittade du ett fel? Rapportera problem →

Exemplen nedan använder Vercels edge-cachning för att servera data till dina användare så snabbt som möjligt.

⚠️ En varning ⚠️

Var alltid försiktig med cachning - särskilt när du hanterar personuppgifter.

Eftersom batchbearbetning är aktiverat som standard rekommenderas det att du sätter dina cache-headers i funktionen responseMeta och ser till att det inte finns samtidiga anrop som kan innehålla personuppgifter - eller att utelämna cache-headers helt om det finns auth-headers eller en cookie.

Du kan också använda en splitLink för att separera dina förfrågningar i publika och privata/icke-cachade.

Appcachning

Om du aktiverar SSR i din app kan du upptäcka att den laddas långsamt på t.ex. Vercel, men du kan faktiskt rendera hela din app statiskt utan SSG; läs den här Twitter-tråden för mer insikter.

Exempelkod

pages/_app.tsx
tsx
export 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 calls
return {
status: config.clientErrors[0].data?.httpStatus ?? 500,
};
}
// cache request for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
return {
headers: {
'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
},
};
},
})(MyApp);
pages/_app.tsx
tsx
export 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 calls
return {
status: config.clientErrors[0].data?.httpStatus ?? 500,
};
}
// cache request for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
return {
headers: {
'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
},
};
},
})(MyApp);

Cachning av API-svar

Eftersom alla frågor är vanliga HTTP GET:ar kan vi använda normala HTTP-headers för att cacha svar, göra svaren blixtsnabb, ge din databas en paus och enklare skala ditt API till otaliga användare.

Använda responseMeta för att cacha svar

Förutsatt att du distribuerar ditt API någonstans som hanterar stale-while-revalidate cache-headers som Vercel.

server.ts
tsx
import * 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 5s
return {
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-export
export type AppRouter = typeof appRouter;
// export API handler
export default trpcNext.createNextApiHandler({
router: appRouter,
createContext,
responseMeta({ ctx, paths, type, errors }) {
// 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 (ctx?.res && allPublic && allOk && isQuery) {
// cache request for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
return {
headers: {
'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
},
};
}
return {};
},
});
server.ts
tsx
import * 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 5s
return {
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-export
export type AppRouter = typeof appRouter;
// export API handler
export default trpcNext.createNextApiHandler({
router: appRouter,
createContext,
responseMeta({ ctx, paths, type, errors }) {
// 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 (ctx?.res && allPublic && allOk && isQuery) {
// cache request for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
return {
headers: {
'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
},
};
}
return {};
},
});