如何在Next.js中为API创建全局错误处理器?
Next.js API 错误处理优化方案(告别重复try-catch)
核心思路:封装统一的错误捕获逻辑
你当前的问题是每个API接口都要手动写try-catch并传入errorHandler,解决这个问题的关键是把错误捕获逻辑封装成通用工具,让所有API路由自动复用,无需重复编写。
1. 封装异步处理包装函数
这是最通用的方案,兼容所有Next.js版本。写一个工具函数,把API的业务逻辑包裹进去,自动捕获异步错误并传给你的errorHandler。
代码示例:
首先创建utils/asyncHandler.js:
const asyncHandler = (fn) => (req, res, next) => { // 自动捕获异步函数的错误,传给next交给errorHandler处理 Promise.resolve(fn(req, res, next)).catch(next); }; module.exports = asyncHandler;
保留你的errorHandler(可微调优化),放在middleware/errorHandler.js:
const errorHandler = (err, req, res, next) => { const statusCode = err.statusCode || 500; const isDevelopment = process.env.NODE_ENV === 'development'; const responseMessage = isDevelopment ? `请求无效:${err.message}` : '服务器内部错误'; return res.status(statusCode).json({ status: false, message: responseMessage, // 开发环境额外返回错误栈,方便调试 ...(isDevelopment && { stack: err.stack }) }); }; module.exports = errorHandler;
在API路由中使用:
比如pages/api/user.js:
import asyncHandler from '../../utils/asyncHandler'; import errorHandler from '../../middleware/errorHandler'; // 可选:自定义错误类,更规范地传递错误信息和状态码 class AppError extends Error { constructor(message, statusCode) { super(message); this.statusCode = statusCode; Error.captureStackTrace(this, this.constructor); } } // 业务逻辑直接写在asyncHandler包裹的函数里,不用手动try-catch const userHandler = asyncHandler(async (req, res) => { if (req.method === 'GET') { // 模拟业务错误 throw new AppError('请求的用户不存在', 404); // 正常逻辑示例: // res.status(200).json({ status: true, data: { id: 1, name: '张三' } }); } else { throw new AppError('不支持该请求方法', 405); } }); // 绑定错误处理中间件 export default (req, res) => userHandler(req, res, errorHandler);
2. 全局API中间件(Next.js 12+)
如果你的项目用Next.js 12及以上版本,可以用API路由中间件实现全局错误处理,不用每个路由单独绑定errorHandler。
代码示例:
在pages/api/_middleware.js中创建全局中间件:
import asyncHandler from '../../utils/asyncHandler'; import errorHandler from '../../middleware/errorHandler'; export default asyncHandler(async (req, event) => { // 先执行下游的API路由逻辑 const response = await event.next(); // 捕获下游返回的错误,交给errorHandler处理 if (response.status >= 400 && response.error) { return errorHandler(response.error, req, response, () => {}); } return response; });
这样所有pages/api/下的路由都会自动应用这个错误处理逻辑,无需每个路由单独配置。
3. App Router 中的错误处理(Next.js 13+)
如果用Next.js 13+的App Router,除了包装函数外,还可以用error.js边界组件实现局部或全局的错误捕获:
单个API路由内的简化处理:
比如app/api/user/route.js:
import { NextResponse } from 'next/server'; class AppError extends Error { constructor(message, statusCode) { super(message); this.statusCode = statusCode; } } export async function GET() { try { throw new AppError('用户不存在', 404); // 正常逻辑: // return NextResponse.json({ status: true, data: { id: 1 } }); } catch (err) { const statusCode = err.statusCode || 500; const isDevelopment = process.env.NODE_ENV === 'development'; const message = isDevelopment ? `请求无效:${err.message}` : '服务器内部错误'; return NextResponse.json({ status: false, message }, { status: statusCode }); } }
全局API错误边界:
在app/api/error.js中创建全局错误组件(仅客户端生效,适合前端展示错误):
'use client'; import { useEffect } from 'react'; export default function Error({ error, reset }) { useEffect(() => { // 可选:上报错误到监控平台 console.error('API错误:', error); }, [error]); return ( <div className="p-4"> <h2>服务器出错了</h2> <p>{process.env.NODE_ENV === 'development' ? error.message : '请稍后重试'}</p> <button onClick={() => reset()} className="mt-2 px-4 py-2 bg-blue-500 text-white rounded"> 重新加载 </button> </div> ); }
总结
- 异步包装函数:最灵活,兼容所有版本,快速解决重复try-catch问题。
- 全局API中间件:Next.js 12+适用,一次性配置所有API路由的错误处理。
- App Router 错误边界:Next.js 13+适用,结合React错误边界实现前后端统一错误展示。
内容的提问来源于stack exchange,提问作者vyom chaudhary
相关产品推荐
相关产品推荐

