Next.js中怎么全局捕获API调用错误?ErrorBoundary没生效

书生シ银银 阅读 109

我在Next.js 13项目里用getServerSideProps调API,但遇到接口报错时页面直接白屏了。按照文档写了组件包裹的ErrorBoundary,但错误信息没被捕获到,控制台只看到”Error: Failed to fetch data”。

尝试在getServerSideProps里加try/catch包裹fetch调用,但错误还是穿透了:


export async function getServerSideProps() {
  try {
    const res = await fetch('/api/data');
    return { props: { data: await res.json() } }
  } catch (err) {
    console.log('caught here'); // 这个日志都没触发
    return { props: { error: 'Failed' } }
  }
}

页面组件里用useState存error状态也没用,直接报错导致SSR渲染失败。应该用什么方式全局处理这种API错误呢?

我来解答 赞 9 收藏
二维码
手机扫码查看
2 条解答
端木静依
你这问题其实不是Next.js的问题,是SSR渲染机制导致的——getServerSideProps里抛出的错误会直接中断整个渲染流程,不会走你组件里的ErrorBoundary,因为组件还没渲染出来呢,错误已经在服务端发生了。

关键点来了:getServerSideProps里必须吞掉错误,并返回一个带error标志的props,别让错误往外抛。

你试了try/catch但日志没触发,说明错误可能不是fetch本身抛的,而是res.json()或者后续逻辑抛的,或者你根本没走到catch块(比如res.ok是false但fetch没报错)。

改法如下:

export async function getServerSideProps() {
try {
const res = await fetch('https://your-api.com/data'); // 注意这里别用相对路径,SSR里/是根路径,不是当前页面路径
if (!res.ok) {
// 显式处理HTTP错误
throw new Error('API error: ' + res.status);
}
const data = await res.json();
return { props: { data, error: null } };
} catch (err) {
console.error('API fetch failed:', err);
// 千万别throw,要返回一个兜底props
return { props: { data: null, error: err.message || 'Failed to fetch data' } };
}
}


然后在页面组件里:

export default function Page({ data, error }) {
if (error) {
return
出错了:{error}
;
}
if (!data) {
return
加载中...
;
}
return
{JSON.stringify(data)}
;
}


另外提醒一句,你用的fetch('/api/data')在SSR环境里可能根本不是调你自己的API路由,因为SSR执行时没有request上下文,相对路径容易出问题,最好写全路径,或者改用getStaticProps + revalidate(如果数据不需要实时性),或者改在客户端用useEffect去fetch(这样ErrorBoundary就能兜住了)。

要是你非要走SSR又想全局处理,可以在_next/server/pages里写个中间件,或者在pages/_app.js里用getInitialProps统一包装——不过得小心,getInitialProps一用整个app就变成SSG模式了,性能和行为都会变,别乱用。

老项目里我一般直接让getServerSideProps里吃掉所有错,返回error字段,前端判断显示。ErrorBoundary只管客户端渲染阶段的错误,服务端的它真管不了。
点赞 5
2026-02-23 18:01
嘉俊🍀
这个问题的根源在于Next.js的服务端渲染机制,ErrorBoundary只能捕获客户端组件的错误,而getServerSideProps是在服务端执行的,所以自然捕获不到。我们需要换个思路来处理。

第一种解决方案是利用getServerSideProps的返回特性,在服务端就处理好错误情况。具体来说可以这样写:

export async function getServerSideProps(context) {
try {
const res = await fetch('http://example.com/api/data');
if (!res.ok) {
// 注意这里要手动判断response状态
return { props: { error: '数据获取失败', errorCode: res.status } };
}
const data = await res.json();
return { props: { data } };
} catch (err) {
// 捕获网络错误或JSON解析错误
return { props: { error: err.message || '未知错误' } };
}
}


这里的关键点是,即使fetch本身没有抛出异常,也要判断response的状态码。因为4xx或5xx的响应在fetch眼里并不算异常,不会进入catch分支。

第二种方法更适合做全局错误处理,可以通过自定义App组件来实现。在pages/_app.js中:

class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps = {};
try {
if (Component.getServerSideProps) {
pageProps = await Component.getServerSideProps(ctx);
}
} catch (error) {
// 全局错误处理逻辑
pageProps = { error: error.message || '服务器错误' };
}
return { pageProps };
}

render() {
const { Component, pageProps } = this.props;
if (pageProps.error) {
return <ErrorPage error={pageProps.error} />;
}
return <Component {...pageProps} />;
}
}


这种方式的好处是可以集中处理所有页面的错误,不过要注意的是,这会影响所有使用getServerSideProps的页面。

另外补充一个细节,你原来的代码中try/catch没生效可能是因为fetch的url是相对路径'/api/data',在服务端渲染时可能会导致DNS解析问题。建议使用完整的绝对路径,或者通过process.env配置API基础路径。

最后说个开发小技巧,可以在next.config.js里配置onError回调,方便调试服务端错误:

module.exports = {
webpack(config, options) {
if (!options.dev) {
config.devtool = 'source-map';
config.optimization.minimize = false;
}
return config;
}
};


这样做虽然会稍微影响生产环境性能,但能显著提升排查服务端错误的效率。记得上线前改回去就是了。
点赞 5
2026-02-14 08:27