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

如何在Next.js开发与生产环境中渲染404页面?

解决Next.js中404页面在生产环境不显示的问题

我完全懂你遇到的糟心情况——本地开发时404页面好好的,一部署到生产环境就没影了。这其实是Next.js在开发/生产环境的错误处理逻辑有差异,再加上之前的实现细节没踩对坑导致的。下面给你梳理靠谱的解决办法:

先纠正一个致命细节:自定义错误页面的命名

你提到创建了_errors.js,但在Next.js的Pages Router体系中,自定义错误页面必须命名为_error.js(单数、下划线开头),而且必须放在项目根目录。命名不对的话,生产环境根本识别不了这个页面,这大概率是你之前方案失效的核心原因之一。

方案1:自定义_error.js页面(推荐,完全可控)

这个方案能让你完全掌控错误页面的样式和内容,同时在开发、生产环境都能稳定生效:

// 项目根目录下的 _error.js
import React from 'react';

class ErrorPage extends React.Component {
  static getInitialProps({ res, err }) {
    // 兼容开发/生产环境的状态码获取:生产从res取,开发从err取
    const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
    return { statusCode };
  }

  render() {
    const { statusCode } = this.props;
    return (
      <div style={{ padding: '2rem', textAlign: 'center' }}>
        <h1>{statusCode} - {statusCode === 404 ? '页面未找到' : '服务器出错了'}</h1>
        <p>
          {statusCode === 404 
            ? '你访问的页面不存在,请检查地址是否正确' 
            : '服务器暂时出现问题,请稍后再试'}
        </p>
      </div>
    );
  }
}

export default ErrorPage;

方案2:在_app.js中配合内置Error组件使用

如果你想复用Next.js自带的Error组件,需要调整状态码的传递逻辑,适配生产环境的处理机制:

// pages/_app.js
import App from 'next/app';
import Error from 'next/error';
import { ApolloProvider } from 'react-apollo';
import Page from '../components/Page';
import withData from '../lib/withData';

class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    let pageProps = {};
    let errorCode = null;

    try {
      if (Component.getInitialProps) {
        pageProps = await Component.getInitialProps(ctx);
      }
      // 检查页面是否返回notFound标记(动态路由场景常用)
      if (pageProps.notFound) {
        errorCode = 404;
        if (ctx.res) ctx.res.statusCode = 404;
      }
      // 捕获服务器返回的错误状态码
      else if (ctx.res && ctx.res.statusCode >= 400) {
        errorCode = ctx.res.statusCode;
      }
    } catch (err) {
      // 捕获数据获取时的异常,比如接口返回404
      errorCode = err.statusCode || 500;
      if (ctx.res) ctx.res.statusCode = errorCode;
    }

    pageProps.query = ctx.query;
    return { pageProps, errorCode };
  }

  render() {
    const { Component, apollo, pageProps, errorCode } = this.props;
    
    if (errorCode) {
      return <Error statusCode={errorCode} />;
    }

    return (
      <ApolloProvider client={apollo}>
        <Page>
          <Component {...pageProps} />
        </Page>
      </ApolloProvider>
    );
  }
}

export default withData(MyApp);

关键补充:动态路由的404触发逻辑

如果你用了动态路由(比如pages/post/[id].js),需要在页面的数据获取方法中,当数据不存在时返回notFound: true,主动告诉Next.js这是个404页面:

// pages/post/[id].js
export async function getServerSideProps(context) {
  const { id } = context.params;
  const postRes = await fetch(`https://your-api.com/posts/${id}`);
  const post = await postRes.json();
  
  // 当接口返回空数据或404时,标记为notFound
  if (!post || postRes.status === 404) {
    return {
      notFound: true,
    };
  }

  return {
    props: { post },
  };
}

为什么之前的方案会失效?

  1. 命名错误:_errors.js不符合Next.js的错误页面命名规范,生产环境无法识别;
  2. 状态码传递逻辑漏洞:生产环境Next.js会优化错误处理流程,单纯读取res.statusCode可能无法正确捕获404状态;
  3. 开发环境的特殊逻辑:开发环境Next.js会强制展示错误页面,但生产环境需要明确通过notFound标记或状态码设置来触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:50:33