升级Next.js至v13版本:ISR错误处理与重验证配置问题
Next.js 13 错误场景下的动态重验证解决方案
针对你从v12升级到v13后无法在错误场景设置60秒重验证的问题,以下是两种贴合你原有逻辑的解决方案:
方案一:复用notFound() + 独立错误页面设置重验证
这个方案完全对应你v12中返回{ notFound: true, revalidate: 60 }的逻辑:
步骤1:在新闻页面组件中捕获错误并触发404
import { notFound } from 'next/navigation'; import type { FetchNews, SimplifiedArticle } from './your-types'; // 你的Firebase数据获取函数保持不变 async function fetchCategoryData(category: string): Promise<SimplifiedArticle[]> { const newsDocRef = collection(firestore, "news"); const q = query( newsDocRef, where("category", "==", category), orderBy("publishedAt", "desc"), limit(5) ); const querySnapshot = await getDocs(q); return querySnapshot.docs.map((doc) => { const docData = doc.data(); return { title: docData.title || "", url: docData.url || "", imageUrl: docData.imageUrl || "", description: docData.description || "", publishedAt: docData.publishedAt || "", content: docData.content || "", source: docData.source || "", }; }); } // 正常页面设置3600秒重验证 export const revalidate = 3600; export default async function NewsPage() { let news: FetchNews; try { // 原有数据获取逻辑迁移到组件内部 news = await Promise.all( categories.map(async (category) => ({ [category]: await fetchCategoryData(category), })) ).then(Object.assign.bind(null, {})); } catch (error) { console.log("News data fetch error: ", error); // 触发404,跳转到对应的not-found页面 notFound(); } // 正常渲染数据 return ( <div className="news-container"> {/* 渲染你的新闻内容 */} </div> ); }
步骤2:创建独立的404错误页面并设置60秒重验证
在你的新闻页面同级目录下创建not-found.tsx(或.jsx):
// app/news/not-found.tsx export const revalidate = 60; // 错误场景下60秒自动重验证 export default function NotFoundPage() { return ( <div className="not-found"> <h2>加载失败,正在重试...</h2> </div> ); }
原理说明:当数据获取失败调用notFound()时,Next.js会渲染这个独立的not-found页面,该页面的revalidate设置为60秒,会自动每1分钟重新尝试获取数据,成功后自动返回正常页面。
方案二:在当前页面处理错误并动态控制缓存
如果你不想跳转到404页面,而是在原页面显示错误状态并动态调整重验证时间,可以使用Next.js的缓存标签功能:
import { revalidateTag, unstable_cache } from 'next/cache'; import type { FetchNews, SimplifiedArticle } from './your-types'; // 用unstable_cache包裹数据获取函数,添加缓存标签 const fetchNewsData = unstable_cache( async () => { return Promise.all( categories.map(async (category) => ({ [category]: await fetchCategoryData(category), })) ).then(Object.assign.bind(null, {})); }, ['news-data-cache'], // 自定义缓存标签 { revalidate: 3600 } // 正常情况3600秒重验证 ); // 你的Firebase数据获取函数保持不变 async function fetchCategoryData(category: string): Promise<SimplifiedArticle[]> { // ... 原有代码 } export default async function NewsPage() { try { const news = await fetchNewsData(); return ( <div className="news-container"> {/* 渲染正常内容 */} </div> ); } catch (error) { console.log("News data fetch error: ", error); // 立即触发缓存重验证,同时设置页面在60秒后再次尝试 await revalidateTag('news-data-cache'); // 显示错误提示 return ( <div className="error-state"> <p>新闻加载失败,将在1分钟后重试</p> </div> ); } } // 基础重验证时间设置为60秒,结合revalidateTag实现动态控制 export const revalidate = 60;
原理说明:通过unstable_cache给数据请求打标签,错误时调用revalidateTag立即清除缓存,同时页面本身设置60秒重验证,确保错误状态下会频繁重试,正常状态下缓存通过unstable_cache的3600秒设置生效。
内容的提问来源于stack exchange,提问作者Tom Fan
相关产品推荐
相关产品推荐

