Chào bạn, có khi nào bạn đang 'lên đời' một ứng dụng web xịn sò với Next.js mà lại gặp phải mấy cái lỗi 'khó ở' không? Tôi đây, trong lúc 'xây nhà' <a href="https://foundersignal.app">FounderSignal</a> – cái nền tảng giúp dân khởi nghiệp 'test' ý tưởng của mình – đã vấp phải một khúc mắc bé tí tẹo mà hóa ra lại cực kỳ 'sát thương' với tính năng fetch revalidation của Next.js. Mà cái này thì dân dev nào cũng nên 'nằm lòng' đó nha! Đừng lo, bài viết này sẽ 'mổ xẻ' vấn đề, kể cho bạn nghe hành trình 'đau khổ' tìm lỗi, và cuối cùng là bật mí giải pháp 'thần thánh', kèm theo cả mấy đoạn code 'xịn xò' và vài bài học xương máu nữa! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/broken_data.png' alt='Dữ liệu bị lỗi, header lạ đời'>Bạn đã sẵn sàng chưa? Let's go!<h3>Vấn đề: Dữ liệu "ôi thiu" và Header "lạ đời"</h3>Tưởng tượng thế này: Tôi muốn cache (lưu trữ tạm thời) các phản hồi từ API cả năm trời lận, nghe sướng không? Với Next.js, tôi dùng ngay cái "bùa chú" `fetch` kèm theo `revalidate` một khoảng thời gian "khủng bố" như thế này:<pre><code>const response = await fetch("https://api.jsonplaceholder.com/v1/users", { next: { revalidate: 31536000 }, // 1 năm = 31536000 giây});</code></pre>Ban đầu thì mọi thứ "ngon ơ" trên máy local và ngay cả lần deploy đầu tiên. Nhưng rồi, sau khi refresh trang trên Vercel, tôi bắt đầu thấy "điềm lạ":<pre><code>content-type: text/xmlcontent-length: 0</code></pre>Chẳng thấy dữ liệu đâu cả! Trong khi API của tôi vẫn trả về JSON "chuẩn cơm mẹ nấu". Oái oăm chưa?<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/debugging.png' alt='Hành trình gỡ lỗi'><h3>Hành trình "đau khổ" tìm lỗi</h3>Lúc đầu, tôi cứ đinh ninh là do API của mình có vấn đề. Tôi "cày" nát log, kiểm tra từng endpoint một, và xác nhận rằng API vẫn "xả" dữ liệu và header đúng phóc.Thế nhưng, cái ứng dụng Next.js đã deploy trên Vercel vẫn cứ "cứng đầu" trả về một phản hồi rỗng tuếch với cái content type "sai lè". Lý do là gì?<img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/long_revalidate_issue.png' alt='Thủ phạm: Revalidation quá dài'><h3>Thủ phạm: Hóa ra là do "thần chú" Revalidation quá "khủng khiếp"!</h3>Sau hàng giờ đồng hồ "vò đầu bứt tai" gỡ lỗi, tôi đã "khui" ra vấn đề: Việc cài đặt `revalidate: 31536000` (tức 1 năm) hoặc thậm chí là `Infinity` đã khiến máy chủ Next.js của Vercel "dở chứng", trả về một phản hồi cache bị hỏng ngay sau lần fetch đầu tiên.Dù tài liệu của <a href="https://nextjs.org/docs/app/api-reference/functions/fetch#optionsnextrevalidate">Next.js</a> có nói rằng `Infinity` được hỗ trợ, nhưng thực tế thì nó lại dẫn đến một loạt "tai họa":<ul><li>Các mục cache bị "ôi thiu" hoặc rỗng tuếch.</li><li>Header `content-type` bị sai.</li><li>Không có dữ liệu nào cho các request sau đó.</li></ul><h3>Giải pháp: Dùng khoảng thời gian Revalidation "hợp tình hợp lý"</h3>"Liều thuốc" hiệu quả nhất lại là một khoảng thời gian revalidation "hiền lành" hơn, chỉ 1 ngày thôi:<pre><code>const response = await fetch("https://api.jsonplaceholder.com/v1/users", { next: { revalidate: 86400 }, // 1 ngày = 86400 giây});</code></pre>Bùm! Giờ đây, mỗi lần refresh trang là dữ liệu lại "tươi rói" và cache hoạt động "mượt mà" như chưa hề có cuộc "chia ly" nào! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/short_revalidate_fix.png' alt='Giải pháp: Revalidation hợp lý'><h3>Những bài học "xương máu" cho dân Dev Next.js</h3><img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/key_takeaways.png' alt='Các bài học quan trọng'><h4>1. Đừng "tham lam" dùng Revalidation quá dài hoặc `Infinity`</h4>Dù tài liệu nói có hỗ trợ `Infinity`, nhưng nó có thể không hoạt động như mong đợi trên tất cả các nền tảng (đặc biệt là Vercel). Cứ "an phận" với các khoảng thời gian thực tế như 1 ngày (86400 giây) hoặc ngắn hơn là "lành" nhất.<h4>2. Luôn "soi" kỹ Response Headers</h4>Nếu bạn thấy `content-type: text/xml` hoặc `content-length: 0` từ một route Next.js mà lẽ ra phải trả về JSON, thì phải "nghi ngờ" ngay là có vấn đề về caching hoặc revalidation đó nha!<h4>3. Gỡ lỗi cả API và Frontend chứ đừng "phiến diện"</h4>Đừng vội đổ lỗi cho API của bạn. Đôi khi, chính lớp caching của framework frontend mới là "thủ phạm" gây ra rắc rối đấy.<h4>4. Dùng Tag-Based Revalidation để "kiểm soát" thủ công</h4>Nếu bạn muốn "giữ" dữ liệu "ôi thiu" một chút cho đến khi có một sự kiện cụ thể xảy ra (ví dụ: có người dùng mới tạo), hãy sử dụng revalidation theo "tag". Nó giống như việc bạn gắn thẻ cho dữ liệu và chỉ làm mới khi bạn "bảo" nó làm vậy:<pre><code>// Fetch dữ liệu với một cái "thẻ"const response = await fetch("https://api.jsonplaceholder.com/v1/users", { next: { tags: ["users"] },});// Trong action hoặc API route của bạn, khi muốn làm mới:import { revalidateTag } from "next/cache";await revalidateTag("users");</code></pre><img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/tag_revalidation.png' alt='Revalidation dựa trên tag'><h3>Kết luận</h3>Caching và revalidation đúng là những tính năng "siêu năng lực" trong Next.js, nhưng chúng cũng dễ "gây họa" nếu bạn không cấu hình cẩn thận. Nếu bạn đang "thai nghén" một dự án như <a href="https://foundersignal.app">FounderSignal</a> hay bất kỳ ứng dụng nào dựa trên dữ liệu, hãy nhớ: luôn kiểm tra chiến lược caching của mình trong môi trường gần giống production nhất và tránh xa các khoảng thời gian revalidation "khủng khiếp" nhé!Bạn có từng gặp phải vấn đề tương tự không? Hãy chia sẻ câu chuyện hoặc câu hỏi của bạn ở phần bình luận bên dưới nha!Chúc bạn "code" vui vẻ, và hy vọng cache của bạn luôn luôn "tươi rói"!
Tìm hiểu cách AI tự hành của Vercel AI SDK, Vector Search của MongoDB và biểu diễn vector của Voyage AI đang cách mạng hóa việc xây dựng đội ngũ trong ngành HR, giúp tìm kiếm nhân tài và quản lý dự án hiệu quả hơn.