Menu

not-found.js

Next.js 提供了两种约定来处理未找到的情况:

  • not-found.js:当你在路由段中调用 notFound 函数时使用。
  • global-not-found.js:用于为整个应用中不匹配的路由定义全局 404 页面。这在路由级别处理,不依赖于渲染 layout 或 page。

not-found.js

not-found 文件用于在路由段中抛出 notFound 函数时渲染 UI。除了提供自定义 UI 外,Next.js 将为流式响应返回 200 HTTP 状态码,为非流式响应返回 404

app/not-found.tsx
TypeScript
import Link from 'next/link'
 
export default function NotFound() {
  return (
    <div>
      <h2>Not Found</h2>
      <p>Could not find requested resource</p>
      <Link href="/">Return Home</Link>
    </div>
  )
}

global-not-found.js(实验性)

global-not-found.js 文件允许你为整个应用定义 404 页面。与在路由级别工作的 not-found.js 不同,当请求的 URL 完全不匹配任何路由时,会使用此文件。Next.js 跳过渲染并直接返回这个全局页面。

global-not-found.js 文件绕过了你应用的正常渲染,这意味着你需要导入 404 页面所需的任何全局样式、字体或其他依赖项。

值得注意的是:使用较小版本的全局样式和更简单的字体系列可以提高此页面的性能。

当你无法使用 layout.jsnot-found.js 的组合来构建 404 页面时,global-not-found.js 很有用。这可能发生在两种情况下:

  • 你的应用有多个根 layout(例如 app/(admin)/layout.tsxapp/(shop)/layout.tsx),因此没有单个 layout 可以组成全局 404。
  • 你的根 layout 使用顶级动态段定义(例如 app/[country]/layout.tsx),这使得组成一致的 404 页面变得更困难。

要启用它,在 next.config.ts 中添加 globalNotFound 标志:

next.config.ts
import type { NextConfig } from 'next'
 
const nextConfig: NextConfig = {
  experimental: {
    globalNotFound: true,
  },
}
 
export default nextConfig

然后,在 app 目录的根目录中创建一个文件:app/global-not-found.js

app/global-not-found.tsx
TypeScript
// 导入全局样式和字体
import './globals.css'
import { Inter } from 'next/font/google'
import type { Metadata } from 'next'
 
const inter = Inter({ subsets: ['latin'] })
 
export const metadata: Metadata = {
  title: '404 - Page Not Found',
  description: 'The page you are looking for does not exist.',
}
 
export default function GlobalNotFound() {
  return (
    <html lang="en" className={inter.className}>
      <body>
        <h1>404 - Page Not Found</h1>
        <p>This page does not exist.</p>
      </body>
    </html>
  )
}

not-found.js 不同,此文件必须返回完整的 HTML 文档,包括 <html><body> 标签。

Reference

Props

not-found.jsglobal-not-found.js 组件不接受任何 props。

值得注意的是:除了捕获预期的 notFound() 错误外,根目录的 app/not-found.jsapp/global-not-found.js 文件还处理整个应用的所有不匹配 URL。这意味着访问你应用未处理的 URL 的用户将看到导出的 UI。

Examples

Data Fetching

默认情况下,not-found 是一个 Server Component。你可以将其标记为 async 来获取和显示数据:

app/not-found.tsx
TypeScript
import Link from 'next/link'
import { headers } from 'next/headers'
 
export default async function NotFound() {
  const headersList = await headers()
  const domain = headersList.get('host')
  const data = await getSiteData(domain)
  return (
    <div>
      <h2>Not Found: {data.name}</h2>
      <p>Could not find requested resource</p>
      <p>
        View <Link href="/blog">all posts</Link>
      </p>
    </div>
  )
}

如果你需要使用 Client Component hooks(如 usePathname)来根据路径显示内容,则必须在客户端获取数据。

Metadata

对于 global-not-found.js,你可以导出 metadata 对象或 generateMetadata 函数来自定义 404 页面的 <title><meta> 和其他 head 标签:

值得注意的是:Next.js 会自动为返回 404 状态码的页面注入 <meta name="robots" content="noindex" />,包括 global-not-found.js 页面。

app/global-not-found.tsx
TypeScript
import type { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: 'Not Found',
  description: 'The page you are looking for does not exist.',
}
 
export default function GlobalNotFound() {
  return (
    <html lang="en">
      <body>
        <div>
          <h1>Not Found</h1>
          <p>The page you are looking for does not exist.</p>
        </div>
      </body>
    </html>
  )
}

Version History

VersionChanges
v15.4.0引入 global-not-found.js(实验性)。
v13.3.0根目录的 app/not-found 处理全局不匹配 URL。
v13.0.0引入 not-found