← 中文资源

简体中文版本

Next SSR 错误边界与恢复

用路由级错误边界包住服务端渲染失败:digest 关联服务端日志,可重试错误提供局部重试按钮,鉴权类失败引导去登录。

阅读英文原文

示例说明

SSR 期间的数据或渲染异常会把整个请求打崩,错误边界把爆炸半径缩到路由段内:页面其余部分照常渲染。Next 的约定文件 error.tsx 自动成为该层边界;error 对象的 digest 是服务端生成的指纹,用它能在服务端日志里精确定位这一场失败——前后端日志靠这个键缝合。

技术要点

  • error.tsx 约定文件自动充当边界
  • digest 连接客户端错误与服务端日志
  • reset 只重渲染出错区段

代码解读

组件按错误内容分流:鉴权类失败渲染引导登录的静态内容;其余可重试错误展示说明与重试按钮,reset 触发该区段重新服务端渲染。useEffect 里的日志记录带 digest,排障时在服务端按指纹检索完整堆栈。

使用建议

不要在边界里吞掉所有错误,未知失败要上报监控。根级 not-found 与 error 分工明确。可重试判定逻辑保持简单,复杂分类放服务端。

代码示例

// serverSide rendering error boundary recovery
// app/dashboard/error.tsx — 路由级错误边界(客户端组件)
'use client';

import { useEffect } from 'react';
import { useRouter } from 'next/navigation';

interface DashboardErrorProps {
  error: Error & { digest?: string };
  reset: () => void;
}

export default function DashboardError({ error, reset }: DashboardErrorProps) {
  const router = useRouter();
  const isRetryable = !error.message.includes('authorization');

  useEffect(() => {
    // digest 由服务端生成,用于在日志中精确定位本次渲染失败
    console.error('dashboard render failed:', error.digest, error.message);
  }, [error]);

  if (!isRetryable) {
    return (
      <section role="alert">
        <h2>Access denied</h2>
        <button onClick={() => router.push('/login')}>Go to login</button>
      </section>
    );
  }

  return (
    <section role="alert">
      <h2>Dashboard failed to render</h2>
      <p>This section hit a transient error. Other page areas still work.</p>
      <button onClick={() => reset()}>Retry this section</button>
    </section>
  );
}

// 服务端组件抛错示例:
// export default async function Page() {
//   const stats = await fetchStats(); // 抛错时仅该段被边界捕获
//   return <StatsCard stats={stats} />;
// }