在Next.js App Router中如何返回404 HTML页面?
在Next.js 13 App Router动态API端点中返回带HTML的404页面
问题场景
在Next.js 13的App Router下创建动态API端点(示例路径:app/some-path/[slug]/route.ts)时,尝试使用notFound()函数返回404状态,但页面仅显示空白。原代码如下:
// app/some-path/[slug]/route.ts import { notFound } from 'next/navigation' export async function GET(request) { notFound() }
现有解决方案
用户目前通过内部fetch项目的/404页面获取HTML内容,再用NextResponse返回带404状态的响应,代码如下:
import { NextResponse } from 'next/server' export default async function notFound(origin) { const fetchRes = await fetch(origin + "/404") const html = await fetchRes.text() console.log(fetchRes.status, fetchRes.statusText); const response = new NextResponse(html, { status: 404, statusText: "Not Found", headers: { "content-type": "text/html" } }); return response; }
但该方案需要额外发起内部请求,流程繁琐,希望得到更正统的实现方式。
正统解决方法
在Next.js 13的App Router中,API路由(route.ts)属于服务端API端点,notFound()默认仅返回空的404响应(因为API路由默认处理数据响应,而非页面渲染)。以下是两种更简洁的正统实现方式:
方法一:直接返回预定义HTML内容
如果404页面内容简单,可直接在API路由中构造HTML字符串,通过NextResponse返回:
// app/some-path/[slug]/route.ts import { NextResponse } from 'next/server' export async function GET(request) { const html = ` <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>404 - 页面未找到</title> <style> body { display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; font-family: sans-serif; } .container { text-align: center; } h1 { font-size: 6rem; color: #333; margin: 0; } p { font-size: 1.2rem; color: #666; } </style> </head> <body> <div class="container"> <h1>404</h1> <p>抱歉,你访问的页面不存在</p> </div> </body> </html> `; return new NextResponse(html, { status: 404, headers: { 'Content-Type': 'text/html' } }); }
方法二:复用App Router的404页面组件
如果已经在app/404.tsx定义了自定义404页面组件,可直接将组件渲染为HTML字符串返回,无需额外fetch:
首先确保存在app/404.tsx组件:
// app/404.tsx export default function NotFoundPage() { return ( <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100vh', margin: 0, fontFamily: 'sans-serif' }}> <div style={{ textAlign: 'center' }}> <h1 style={{ fontSize: '6rem', color: '#333', margin: 0 }}>404</h1> <p style={{ fontSize: '1.2rem', color: '#666' }}>抱歉,你访问的页面不存在</p> </div> </div> ); }
然后在API路由中使用renderToStaticMarkup将组件转为HTML:
// app/some-path/[slug]/route.ts import { NextResponse } from 'next/server'; import { renderToStaticMarkup } from 'react'; import NotFoundPage from '../../404'; export async function GET(request) { const html = ` <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>404 - 页面未找到</title> </head> <body>${renderToStaticMarkup(<NotFoundPage />)}</body> </html> `; return new NextResponse(html, { status: 404, headers: { 'Content-Type': 'text/html' } }); }
这种方式复用已有组件,避免代码重复,效率更高,也更贴合Next.js的设计逻辑。
内容的提问来源于stack exchange,提问作者Kenneth Spencer
相关产品推荐
相关产品推荐

