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

非静态Next.js App Router应用:需可自定义信息的静态错误页模板

解决方案

你遇到的问题核心是:Next.js生成的_not-found.html在React hydration时,会用组件硬编码的内容覆盖你手动修改的HTML文本。要实现可自定义错误信息且保留站点布局的静态错误页,有两种可行方案:

方案一:支持React Hydration的动态错误页模板

这个方案保留React的交互能力和styled-components样式,同时允许后端注入自定义错误信息。

1. 创建专用错误页组件

在app/backend-error/page.tsx中编写组件,从DOM隐藏元素读取初始错误信息,避免hydration覆盖:

'use client';
import { useEffect, useState } from 'react';
import { SiteLayout, GlobalStyles } from '@/components/layout'; // 替换为你的站点布局组件

export default function BackendErrorPage() {
  const [errorCode, setErrorCode] = useState('500');
  const [errorMessage, setErrorMessage] = useState('服务器内部错误');

  useEffect(() => {
    // 从DOM读取后端注入的错误数据
    const codeEl = document.getElementById('backend-error-code');
    const msgEl = document.getElementById('backend-error-message');
    
    if (codeEl) setErrorCode(codeEl.textContent || '500');
    if (msgEl) setErrorMessage(msgEl.textContent || '服务器内部错误');
  }, []);

  return (
    <html lang="zh-CN">
      <body>
        <GlobalStyles />
        <SiteLayout>
          <div style={{ padding: '2rem', textAlign: 'center' }}>
            <h1 style={{ fontSize: '2rem', marginBottom: '1rem' }}>错误 {errorCode}</h1>
            <p style={{ fontSize: '1.2rem' }}>{errorMessage}</p>
          </div>
        </SiteLayout>
      </body>
    </html>
  );
}

2. 生成静态HTML模板

编写Node.js脚本,用ReactDOMServer渲染组件并生成完整HTML,同时预留注入错误信息的隐藏元素:

import React from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import BackendErrorPage from './app/backend-error/page.tsx';
import fs from 'fs';

// 渲染组件为静态标记
const componentHtml = renderToStaticMarkup(<BackendErrorPage />);

// 拼接完整HTML,复制你的站点head资源(从Next.js生成的页面中复制)
const fullHtml = `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>错误页面</title>
  <!-- 复制Next.js生成的head资源,确保样式和脚本正常加载 -->
  <link rel="stylesheet" href="/_next/static/css/[hash].css">
  <script src="/_next/static/chunks/webpack.js"></script>
  <script src="/_next/static/chunks/main-app.js"></script>
</head>
<body>
  <!-- 预留的错误信息注入点 -->
  <div id="backend-error-code" style="display: none;"></div>
  <div id="backend-error-message" style="display: none;"></div>
  ${componentHtml}
</body>
</html>
`;

// 保存为模板文件
fs.writeFileSync('./backend-error-template.html', fullHtml);

3. 后端注入错误信息

Python后端读取模板文件,替换隐藏元素的内容后返回:

import html

def get_error_page(error_code: str, error_message: str) -> tuple[str, int]:
    with open('./backend-error-template.html', 'r', encoding='utf-8') as f:
        template = f.read()
    
    # 转义内容防止XSS攻击
    safe_code = html.escape(error_code)
    safe_msg = html.escape(error_message)
    
    # 替换模板中的标记
    final_html = template.replace(
        '<div id="backend-error-code" style="display: none;"></div>',
        f'<div id="backend-error-code" style="display: none;">{safe_code}</div>'
    ).replace(
        '<div id="backend-error-message" style="display: none;"></div>',
        f'<div id="backend-error-message" style="display: none;">{safe_msg}</div>'
    )
    
    return final_html, int(error_code)

方案二:纯静态无Hydration的错误页模板

如果不需要React交互,只保留样式和布局,可以生成完全静态的HTML,避免hydration问题:

1. 生成带内联样式的静态HTML

使用styled-components的ServerStyleSheet提取样式并嵌入HTML:

import React from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { ServerStyleSheet } from 'styled-components';
import BackendErrorPage from './app/backend-error/page.tsx';
import fs from 'fs';

const sheet = new ServerStyleSheet();
try {
    const componentHtml = renderToStaticMarkup(sheet.collectStyles(<BackendErrorPage />));
    const styleTags = sheet.getStyleTags();

    const fullHtml = `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>错误页面</title>
  ${styleTags}
</head>
<body>
  <div id="backend-error-code" style="display: none;"></div>
  <div id="backend-error-message" style="display: none;"></div>
  ${componentHtml}
</body>
</html>
`;

    fs.writeFileSync('./backend-error-static.html', fullHtml);
} catch (err) {
    console.error('生成静态错误页失败:', err);
} finally {
    sheet.seal();
}

2. 后端使用方式

和方案一的Python代码一致,替换隐藏元素内容后返回即可。

关键说明

  • 直接修改_not-found.html无效的原因:Next.js的错误页组件是硬编码内容,hydration时虚拟DOM会覆盖真实DOM的手动修改。
  • 两种方案都需要做XSS防护:用html.escape()处理用户输入的错误信息,避免注入攻击。

内容的提问来源于stack exchange,提问作者jaboja

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 03:15:02