You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 11:37:38