응답 캐싱
비공식 베타 번역
이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →
모든 tRPC 쿼리는 일반 HTTP GET 요청이므로, 표준 HTTP 캐시 헤더를 사용해 응답을 캐시할 수 있습니다. 이렇게 하면 응답 속도가 빨라지고, 데이터베이스 부하를 줄일 수 있으며, API 확장성을 높이는 데 도움이 됩니다.
정보
캐싱 사용 시 항상 주의하세요 - 특히 개인 정보를 다루는 경우 더욱 신경 써야 합니다.
기본적으로 배칭(batching)이 활성화되어 있으므로, responseMeta 함수에서 캐시 헤더를 설정할 때 개인 데이터가 포함될 수 있는 동시 호출이 없는지 반드시 확인하세요. 또는 인증 헤더나 쿠키가 있는 경우 캐시 헤더를 완전히 생략하는 것도 방법입니다.
splitLink를 사용해 공개 요청과 비공개로 유지되며 캐시되지 않아야 하는 요청을 분리할 수도 있습니다.
responseMeta를 활용한 응답 캐싱
대부분의 tRPC 어댑터는 호출되는 프로시저를 기반으로 HTTP 헤더(캐시 헤더 포함)를 설정할 수 있는 responseMeta 콜백을 지원합니다.
이 방법은 표준 HTTP 캐시 헤더를 지원하는 모든 호스팅 제공업체(Vercel, Cloudflare, AWS CloudFront 등)에서 동작합니다.
server.tstsimport {initTRPC } from '@trpc/server';import {createHTTPServer } from '@trpc/server/adapters/standalone';import type {CreateHTTPContextOptions } from '@trpc/server/adapters/standalone';export constcreateContext = async (opts :CreateHTTPContextOptions ) => {return {req :opts .req ,res :opts .res ,};};typeContext =Awaited <ReturnType <typeofcreateContext >>;export constt =initTRPC .context <Context >().create ();constwaitFor = async (ms : number) =>newPromise ((resolve ) =>setTimeout (resolve ,ms ));export constappRouter =t .router ({public :t .router ({slowQueryCached :t .procedure .query (async (opts ) => {awaitwaitFor (5000); // wait for 5sreturn {lastUpdated : newDate ().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-exportexport typeAppRouter = typeofappRouter ;// export API handlerconstserver =createHTTPServer ({router :appRouter ,createContext ,responseMeta (opts ) {const {paths ,errors ,type } =opts ;// assuming you have all your public routes with the keyword `public` in themconstallPublic =paths &&paths .every ((path ) =>path .includes ('public'));// checking that no procedures erroredconstallOk =errors .length === 0;// checking we're doing a query requestconstisQuery =type === 'query';if (allPublic &&allOk &&isQuery ) {// cache request for 1 day + revalidate once every secondconstONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers : newHeaders ([['cache-control',`s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS }`,],]),};}return {};},});server .listen (3000);
server.tstsimport {initTRPC } from '@trpc/server';import {createHTTPServer } from '@trpc/server/adapters/standalone';import type {CreateHTTPContextOptions } from '@trpc/server/adapters/standalone';export constcreateContext = async (opts :CreateHTTPContextOptions ) => {return {req :opts .req ,res :opts .res ,};};typeContext =Awaited <ReturnType <typeofcreateContext >>;export constt =initTRPC .context <Context >().create ();constwaitFor = async (ms : number) =>newPromise ((resolve ) =>setTimeout (resolve ,ms ));export constappRouter =t .router ({public :t .router ({slowQueryCached :t .procedure .query (async (opts ) => {awaitwaitFor (5000); // wait for 5sreturn {lastUpdated : newDate ().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-exportexport typeAppRouter = typeofappRouter ;// export API handlerconstserver =createHTTPServer ({router :appRouter ,createContext ,responseMeta (opts ) {const {paths ,errors ,type } =opts ;// assuming you have all your public routes with the keyword `public` in themconstallPublic =paths &&paths .every ((path ) =>path .includes ('public'));// checking that no procedures erroredconstallOk =errors .length === 0;// checking we're doing a query requestconstisQuery =type === 'query';if (allPublic &&allOk &&isQuery ) {// cache request for 1 day + revalidate once every secondconstONE_DAY_IN_SECONDS = 60 * 60 * 24;return {headers : newHeaders ([['cache-control',`s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS }`,],]),};}return {};},});server .listen (3000);
팁
Next.js를 사용 중이라면, createTRPCNext와 Next.js 어댑터를 활용한 Next.js 전용 캐싱 예제를 보려면 Next.js SSR 캐싱 가이드를 참조하세요.