Next.js调用notFound()返回404页面但响应码为200问题排查
解决方案:让Next.js App Router同时返回404页面和404状态码
问题根源
你的代码中使用Promise.all并行发起验证请求与其他数据请求,当验证请求失败后调用notFound()时,其他请求可能已开始处理,导致Next.js无法正确设置404响应状态码。此外,若页面被静态缓存,也会出现状态码不匹配的情况。
修复步骤
1. 优先单独执行验证请求
不要并行发起验证和其他请求,先完成验证逻辑,确认通过后再获取其他数据。这样能确保验证失败时立即终止页面渲染,让Next.js正确设置404状态码。
修改后的代码:
// page.tsx import { CategoryPage } from './CategoryPage'; import CategoryHead from './CategoryHead'; import { notFound } from 'next/navigation'; export default async function ExamCategoryPage({ params }: { params: { category: string } }) { const { category } = params; // 先执行验证请求,失败直接返回404 const validationRes = await fetch( `${process.env.NEXT_PUBLIC_BASE_URL}/api/categories/validate-path/${category}`, { next: { revalidate: 900 } } ); if (!validationRes.ok) { notFound(); } // 验证通过后,再获取其他数据 const [categoryRes, examRes] = await Promise.all([ fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/categories/slug/${category}`, { next: { revalidate: 1200 } }), fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/exam/exam/${category}`) ]); const [categoryData, examData] = await Promise.all([ categoryRes.json(), examRes.json() ]); if (!categoryData.success) { notFound(); } return ( <div> <CategoryHead category={categoryData.data} subcategories={categoryData.data.children || []} /> <CategoryPage examData={examData.success ? examData.data : null} /> </div> ); }
2. 确保验证API返回正确的4xx状态码
确认/api/categories/validate-path/${category}接口在路径无效时,返回404或其他4xx系列状态码,而非200加错误信息。validationRes.ok仅识别200-299的状态码为成功,若接口返回200但success: false,则不会触发notFound()。
3. 禁用静态缓存(可选)
如果页面被静态生成,可能导致状态码被缓存为200。可在页面级别强制服务器端渲染:
export const dynamic = 'force-dynamic';
或在fetch中添加cache: 'no-store'(适用于动态内容场景)。
验证效果
修改后访问无效的category路径时:
- 页面会显示Next.js默认404页面
- 网络面板中页面请求的响应码应为404
内容的提问来源于stack exchange,提问作者Siddhesh Haryan
相关产品推荐
相关产品推荐

