Önbellekleme ve yeniden doğrulama

Rota segmenti yapılandırması, unstable_cache, revalidateTag / revalidatePath ve stale-while-revalidate.

Rota işleyicisi yanıtlarını ve verileri önbelleğe alın, ardından zamanlayıcıyla veya talep üzerine yeniden doğrulayın. Arka planda tek bir yenileme çalışırken güncelliğini yitirmiş girdiler hemen sunulur.

Rota işleyicileri

GET rota işleyicileri varsayılan olarak dinamiktir. Önbelleğe almayı rota segmenti yapılandırmasıyla etkinleştirin:

app/api/posts/route.tsts
export const revalidate = 60;export async function GET() {  const posts = await db.posts.latest();  return Response.json(posts);}
Dışa aktarımDavranış
(yok)Her istekte çalışır
dynamic = "force-static"Yeniden doğrulanana kadar önbelleğe alınır
revalidate = NÖnbelleğe alınır; N saniye sonra güncelliğini yitirir
revalidate = 0 veya dynamic = "force-dynamic"Her istekte çalışır

Diğer dynamic değerleri TX031 hatasıyla başarısız olur. Text.js bir işleyicinin isteği ne zaman okuduğunu algılayamadığı için Next.js’in "error" değeri de buna dahildir.

Önbelleğe alınan işleyicilerde her yol adı için bir girdi bulunur ve request derleme zamanındaki gibi görünür: sorgu dizesi, üstbilgiler, çerezler veya gövde içermez. Bunları dinamik bir işleyicide okuyun. Yalnızca GET ve HEAD önbelleğe alınır. 5xx durumu, Set-Cookie üstbilgisi veya Cache-Control: private / no-store içeren yanıtlar döndürülür ancak hiçbir zaman saklanmaz.

Üstbilgiler

Önbelleğe alınan yanıtlar şunları taşır:

ÜstbilgiDeğer
x-textjs-cacheMISS, HIT veya STALE
Cache-Controls-maxage=N, stale-while-revalidate=<1 year − N> veya force-static için s-maxage=31536000

Ara katman istek için çerez ayarladığında, yeniden yazma yaptığında veya istek üstbilgilerini geçersiz kıldığında, üretilen üstbilgi private, no-cache, no-store, max-age=0, must-revalidate olur; böylece paylaşılan önbellekler ziyaretçiye özgü bir kararı hiçbir zaman tekrar sunmaz. İşleyicinin ayarladığı Cache-Control üstbilgisi korunur.

text dev komutunda segment yapılandırması uygulanır ancak hiçbir şey saklanmaz; bu nedenle her istek işleyiciyi çalıştırır.

Veri önbelleği

Herhangi bir asenkron fonksiyonu @textjs/app/cache paketindeki unstable_cache ile önbelleğe alın:

lib/posts.tsts
import { unstable_cache } from "@textjs/app/cache";export const getPosts = unstable_cache(  async (author: string) => db.posts.byAuthor(author),  ["posts"],  { tags: ["posts"], revalidate: 300 },);

Anahtar, değere göre kodlanmış anahtar parçaları ve argümanlardan oluşur (undefined ve null, Map, Set, Date ve URL argümanları birbirinden ayrı kalır). Anahtar parçaları yoksa fonksiyonu kaynak kodu ve oluşturulduğu yer tanımlar; fonksiyon dış kapsamındaki değerleri kullandığında, örneğin her istek için veya bir döngü içinde oluşturulduğunda, anahtar parçalarını iletin. Sonuçlar JSON olarak serileştirilir; bu nedenle her çağrı yeni bir kopya döndürür (ve Date nesneleri dize olarak geri döner); serileştirilemeyen bir sonuç hata fırlatır. cache(fn, { key, tags, revalidate }) aynı ayarları bir seçenekler nesnesi olarak alır.

Önbelleğe alınmış bir rota işleyicisinde veri girdileri, etiketlerini ve en kısa revalidate değerlerini rotaya aktarır: "posts" etiketini yeniden doğrulamak /api/posts yolunu da yeniler. revalidate: 0 içeren bir veri çağrısı rotayı dinamik hale getirir.

Yeniden doğrulama sırasında eski veriyi sunma

Bir girdinin yaşı revalidate değerini aştığında:

  1. Sonraki istek güncelliğini yitirmiş değeri hemen alır (STALE).
  2. Arka planda tek bir yenileme çalışır; eşzamanlı istekler bunu paylaşır.
  3. Yenileme hata fırlatırsa güncelliğini yitirmiş değer sunulmaya devam eder ve hata günlüğe kaydedilir.

Vercel ve Cloudflare’da arka plan yenilemeleri waitUntil() ile kaydedilir. Bir yıldan eski girdiler her zaman ön planda yeniden hesaplanır.

Talep üzerine yeniden doğrulama

app/api/revalidate/route.tsts
import { revalidatePath, revalidateTag } from "@textjs/app/cache";export async function POST(request: Request) {  // Anyone can POST here: require a secret shared with your CMS or webhook.  if (request.headers.get("authorization") !== `Bearer ${process.env.REVALIDATE_SECRET}`) {    return new Response("Unauthorized", { status: 401 });  }  await revalidateTag("posts");  await revalidatePath("/api/feed");  return Response.json({ revalidated: true });}
ÇağrıGeçersiz kıldıkları
revalidateTag("posts")posts etiketli her şey; sonraki istekte yeniden hesaplanır
revalidateTag("posts", "max")Güncelliğini yitirmiş olarak işaretler; yenilenirken sonraki isteğe eski değer sunulur
revalidatePath("/api/feed")Belirtilen yol
revalidatePath("/api/posts/[id]")Dinamik bir rotanın tüm yolları
revalidatePath("/api", "layout")/api altındaki her şey

İkisi de bir promise döndürür. Bellek içi depoda geçersiz kılma hemen gerçekleşir; özel depo asenkron olduğunda await ile bekleyin.

Özel önbellek depoları

Varsayılan depo, her sunucu örneği için bellek içi bir LRU’dur (1.000 girdi, yaklaşık 50 MB). Örnekler arasında önbellek paylaşmak için cacheHandler değerini, varsayılan dışa aktarımı bir CacheStore olan modüle yönlendirin:

text.config.tsts
export default defineConfig({ cacheHandler: "./cache-handler.ts" });
cache-handler.tsts
import type { CacheStore } from "@textjs/app/cache";const store: CacheStore = {  async get(key) { return redis.get(key).then((v) => (v ? JSON.parse(v) : undefined)); },  async set(key, entry) { await redis.set(key, JSON.stringify(entry)); },  async delete(key) { await redis.del(key); },  async markTags(tags, mode, at) { for (const t of tags) await redis.hset(`tag:${t}`, mode, at); },  async getTagState(tags) { /* max expiredAt / staleAt across tags */ return { expiredAt: 0, staleAt: 0 }; },};export default store;

Girdiler düz JSON’dur. Alternatif olarak setCacheStore(store) çalışma zamanında bir depo kurar.

Platform notları

  • Her sunucusuz örneğin (Vercel fonksiyonları, Cloudflare isolate’leri) kendi bellek içi önbelleği vardır. Cache-Control: s-maxage, platform CDN’inin de yanıtları önbelleğe almasını sağlar; talep üzerine yeniden doğrulama CDN önbelleğini temizlemez. revalidateTag her örneğe ulaşmalıysa paylaşılan bir cacheHandler kullanın.
  • Cloudflare, nodejs_compat bayrağını gerektirir (önbellek AsyncLocalStorage kullanır). Dağıtım bölümüne bakın.
Bu sayfayı GitHub’da düzenle