异常处理
DoraCMS 提供了统一的异常处理体系,支持跨数据库异常统一、自定义异常类型和清晰的错误信息。
异常处理机制
统一异常类型
javascript
// 内置异常类型
class ValidationError extends Error {
constructor(message) {
super(message)
this.name = 'ValidationError'
this.status = 400
}
}
class NotFoundError extends Error {
constructor(resource) {
super(`${resource} not found`)
this.name = 'NotFoundError'
this.status = 404
}
}
class UniqueConstraintError extends Error {
constructor(field) {
super(`${field} already exists`)
this.name = 'UniqueConstraintError'
this.status = 409
}
}
class PermissionError extends Error {
constructor(message) {
super(message || 'Permission denied')
this.name = 'PermissionError'
this.status = 403
}
}Repository 层异常处理
创建操作异常
javascript
async create(data) {
try {
return await this.model.create(data)
} catch (error) {
// MongoDB 唯一性约束
if (error.code === 11000) {
const field = Object.keys(error.keyPattern)[0]
throw new UniqueConstraintError(field)
}
// MariaDB 唯一性约束
if (error.name === 'SequelizeUniqueConstraintError') {
const field = error.errors[0].path
throw new UniqueConstraintError(field)
}
throw error
}
}查询操作异常
javascript
async findById(id) {
const item = await this.model.findById(id)
if (!item) {
throw new NotFoundError(this.model.modelName)
}
return item
}全局错误处理
javascript
// app/middleware/error_handler.js
module.exports = () => {
return async function errorHandler(ctx, next) {
try {
await next()
} catch (err) {
// 记录错误日志
ctx.logger.error(err)
// 设置响应状态码
ctx.status = err.status || 500
// 设置响应体
ctx.body = {
code: ctx.status,
message: err.message,
...(ctx.app.config.env === 'local' && { stack: err.stack })
}
}
}
}使用示例
Service 层
javascript
class UserService extends Service {
async createUser(userData) {
try {
return await this.ctx.repo.user.create(userData)
} catch (error) {
if (error.name === 'UniqueConstraintError') {
throw new Error(`用户${error.message}`)
}
throw error
}
}
}Controller 层
javascript
class UserController extends Controller {
async create() {
try {
const user = await this.ctx.service.user.createUser(this.ctx.request.body)
this.ctx.body = { code: 0, data: user }
} catch (error) {
this.ctx.body = {
code: error.status || 500,
message: error.message
}
}
}
}最佳实践
- ✅ 使用统一的异常类型
- ✅ 在 Repository 层转换数据库异常
- ✅ 在 Service 层添加业务上下文
- ✅ 在 Controller 层统一格式化响应
- ✅ 记录详细的错误日志