Mục lục

Advanced Patterns: Security & Caching

Bảo vệ dữ liệu nhạy cảm với 'server-only'. Hiểu sâu 4 tầng Caching của Next.js: Request Memoization, Data Cache, Full Route Cache và Router Cache.

Để trở thành chuyên gia App Router, bạn phải nắm vững cách Next.js lưu trữ dữ liệu và cách bảo mật code của mình.

1. Bảo mật với server-only

Trong App Router, một file Server Component có thể vô tình bị import vào một Client Component. Nếu file đó chứa logic nhạy cảm (API Key, Database Secret), nó sẽ bị gửi về trình duyệt -> Lỗ hổng bảo mật.

Giải pháp: Sử dụng package server-only.

bash:
npm install server-only
ts:
// lib/db-secret.ts
import 'server-only'; // 👈 Nếu ai đó import file này vào "use client", Next.js sẽ báo lỗi ngay khi build

export const API_KEY = process.env.SECRET_KEY;
export const db = ...;

2. Hệ thống Caching 4 tầng

Next.js App Router rất "mạnh tay" trong việc cache. Bạn phải hiểu để tránh lỗi "Data không cập nhật".

Tầng 1: Request Memoization

React tự động cache các request fetch GIỐNG HỆT NHAU trong cùng một chu kỳ render (một lần tải trang).

  • Lợi ích: Bạn có thể gọi fetchUser() ở 5 component khác nhau, nhưng thực tế chỉ có 1 request được gửi đi.

Tầng 2: Data Cache

Next.js lưu trữ kết quả fetch qua nhiều request của nhiều người dùng khác nhau trên hệ thống.

  • Duy trì: Vĩnh viễn (mặc định) cho đến khi revalidate.
  • Cấu hình: { next: { revalidate: 3600 } }.

Tầng 3: Full Route Cache

Next.js render sẵn toàn bộ trang HTML và RSC Payload tại thời điểm build (Static Rendering).

  • Mục tiêu: Tải trang ngay lập tức.

Tầng 4: Router Cache

Đây là cache phía Client (Trình duyệt). Next.js lưu trữ các trang bạn đã đi qua để khi bấm "Back", trang hiện ra tức thì mà không cần load lại.

3. Data Flow Pattern: Preloading

Nếu bạn có một cây component sâu và cần data, thay vì Waterfall (đợi cha xong rồi đến con), hãy dùng pattern Preload.

ts:
// components/User.tsx
import { getUser } from '@/lib/api';

export const preload = (id: string) => {
  // Bắt đầu fetch sớm nhất có thể nhưng không đợi (non-blocking)
  void getUser(id);
};

export default async function User({ id }: { id: string }) {
  const user = await getUser(id); // Lúc này data có thể đã có sẵn trong cache memoization
  return <div>{user.name}</div>;
}

4. Server-Only Context (Singleton Pattern)

Trong Server Components, không có React Context. Nếu bạn muốn share dữ liệu xuyên suốt một request (ví dụ: currentUser), hãy dùng module singleton hoặc thư viện cache của React.

ts:
// lib/get-user.ts
import { cache } from 'react';

export const getCurrentUser = cache(async () => {
  // Logic fetch user dựa trên cookie
  return await db.user.findFirst(...);
});

Nhờ hàm cache, dù bạn gọi getCurrentUser() bao nhiêu lần trong 1 request, logic chỉ chạy 1 lần.

Kết luận

  • Luôn dùng server-only cho các file chứa secrets.
  • Hiểu rõ Data Cache để biết khi nào cần dùng force-dynamic hoặc revalidatePath.
  • Tận dụng cache của React để thay thế cho Context API trên Server.
Quảng cáo
mdhorizontal