Node.js 错误对象与自定义错误
Error 对象是 Node.js 错误处理的核心。
Error 对象属性
标准属性
JavaScript
const err = new Error('出错了');
console.log(err.message); // '出错了' - 错误描述
console.log(err.name); // 'Error' - 错误类型名
console.log(err.stack); // 堆栈追踪字符串
扩展属性
JavaScript
const err = new Error('数据库连接失败');
err.code = 'ECONNREFUSED';
err.statusCode = 500;
err.details = { host: 'localhost', port: 3306 };
console.log(err.code); // 'ECONNREFUSED'
console.log(err.statusCode); // 500
内置错误类型
Error 类型列表
| 类型 | 说明 | 触发场景 |
|---|---|---|
| Error | 通用错误 | throw new Error() |
| TypeError | 类型错误 | 对错误类型调用方法 |
| RangeError | 范围错误 | 数值超出有效范围 |
| ReferenceError | 引用错误 | 访问未定义变量 |
| SyntaxError | 语法错误 | 解析语法错误 |
| URIError | URI错误 | encodeURI/decodeURI 失败 |
| SystemError | 系统错误 | 文件/网络操作失败 |
使用示例
JavaScript
// TypeError
try {
null.method();
} catch (err) {
console.log(err.name); // TypeError
console.log(err.message); // Cannot read property 'method' of null
}
// RangeError
try {
new Array(-1);
} catch (err) {
console.log(err.name); // RangeError
}
// ReferenceError
try {
console.log(undefinedVar);
} catch (err) {
console.log(err.name); // ReferenceError
}
系统错误属性
JavaScript
// 系统错误(fs、net等)额外属性
fs.readFile('notexist.txt', (err, data) => {
if (err) {
console.log(err.code); // 'ENOENT' - 错误码
console.log(err.syscall); // 'open' - 系统调用
console.log(err.path); // 'notexist.txt' - 文件路径
console.log(err.errno); // -2 - 错误号
}
});
自定义错误类
基本自定义错误
JavaScript
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = 'ValidationError';
}
}
throw new ValidationError('输入验证失败');
添加额外属性
JavaScript
class ValidationError extends Error {
constructor(message, field, value) {
super(message);
this.name = 'ValidationError';
this.field = field;
this.value = value;
this.statusCode = 400;
}
}
// 使用
try {
throw new ValidationError('邮箱格式错误', 'email', 'invalid-email');
} catch (err) {
console.log({
name: err.name,
message: err.message,
field: err.field,
value: err.value,
statusCode: err.statusCode
});
}
业务错误类
JavaScript
class BusinessError extends Error {
constructor(message, code, statusCode = 500) {
super(message);
this.name = 'BusinessError';
this.code = code;
this.statusCode = statusCode;
this.timestamp = new Date().toISOString();
this.isOperational = true; // 标记为可操作错误
}
}
class NotFoundError extends BusinessError {
constructor(resource) {
super(`${resource} 不存在`, 'NOT_FOUND', 404);
this.name = 'NotFoundError';
this.resource = resource;
}
}
class UnauthorizedError extends BusinessError {
constructor(message = '未授权访问') {
super(message, 'UNAUTHORIZED', 401);
this.name = 'UnauthorizedError';
}
}
数据库错误
JavaScript
class DatabaseError extends Error {
constructor(message, query, originalError) {
super(message);
this.name = 'DatabaseError';
this.query = query;
this.originalError = originalError;
this.statusCode = 500;
}
}
try {
await db.query('SELECT * FROM users');
} catch (err) {
throw new DatabaseError('查询失败', 'SELECT * FROM users', err);
}
错误类使用
分类处理
JavaScript
function handleError(err) {
if (err instanceof ValidationError) {
return {
status: err.statusCode,
body: { error: err.message, field: err.field }
};
}
if (err instanceof NotFoundError) {
return {
status: 404,
body: { error: err.message }
};
}
if (err instanceof DatabaseError) {
logger.error('数据库错误:', err.originalError);
return {
status: 500,
body: { error: '服务器内部错误' }
};
}
// 未知错误
logger.error(err.stack);
return {
status: 500,
body: { error: '未知错误' }
};
}
Express 中使用
JavaScript
// 路由中使用
app.get('/user/:id', async (req, res, next) => {
const user = await User.findById(req.params.id);
if (!user) {
return next(new NotFoundError('用户'));
}
res.json(user);
});
// 错误处理中间件
app.use((err, req, res, next) => {
const statusCode = err.statusCode || 500;
res.status(statusCode).json({
error: err.message,
code: err.code
});
});
错误堆栈
获取堆栈
JavaScript
const err = new Error('测试');
console.log(err.stack);
// 输出格式
// Error: 测试
// at Object.<anonymous> (/path/file.js:10:11)
// at Module._compile (internal/modules/cjs/loader.js:...)
自定义堆栈捕获点
JavaScript
class CustomError extends Error {
constructor(message) {
super(message);
// 捕获当前点堆栈,排除构造函数
Error.captureStackTrace(this, CustomError);
}
}
注意事项
- 自定义错误必须继承 Error
- 调用
super(message)设置 message- 设置
name属性标识错误类型- 添加 statusCode 方便 HTTP 响应
- 使用
isOperational区分可恢复错误
要点总结
- Error 有 message、name、stack 属性
- 系统错误有 code、syscall、path 等
- 自定义错误继承 Error 并扩展属性
- 添加 statusCode 和 code 便于处理
- 使用 instanceof 分类处理错误
📝 发现内容有误?点击此处直接编辑