Skip to content

异常处理

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
      }
    }
  }
}

最佳实践

  1. ✅ 使用统一的异常类型
  2. ✅ 在 Repository 层转换数据库异常
  3. ✅ 在 Service 层添加业务上下文
  4. ✅ 在 Controller 层统一格式化响应
  5. ✅ 记录详细的错误日志