如何在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 }, }; }
为什么之前的方案会失效?
- 命名错误:
_errors.js不符合Next.js的错误页面命名规范,生产环境无法识别; - 状态码传递逻辑漏洞:生产环境Next.js会优化错误处理流程,单纯读取
res.statusCode可能无法正确捕获404状态; - 开发环境的特殊逻辑:开发环境Next.js会强制展示错误页面,但生产环境需要明确通过
notFound标记或状态码设置来触发。
内容的提问来源于stack exchange,提问作者Aviwe
相关产品推荐
相关产品推荐

