我为我的数据库定义了一堆续集模型。我们使用 Express 创建 CRUD API 来处理数据库操作,UI 将调用这些 API 进行用户交互。现在我最关心的是向用户返回适当的错误消息。 UI 可以简单地渲染这些后端 API 返回的错误响应。当未清理的错误消息很敏感并且可能会将底层功能暴露给外界时,这就变得具有挑战性。
这些是我遇到的不同类型的错误:
1.
errors: [
ValidationErrorItem {
message: 'Student.CourseID cannot be null',
type: 'notNull Violation',
path: 'CourseID',
value: null,
origin: 'CORE',
instance: [Student],
validatorKey: 'is_null',
validatorName: null,
validatorArgs: []
}]
name: 'SequelizeForeignKeyConstraintError',
parent: RequestError: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Org_Student". The conflict occurred in database "school", table "dbo.Course", column 'CourseID'.
AggregateError
[errors]: [
RequestError: Invalid column name 'createdAt'.
...
]
name: 'SequelizeUniqueConstraintError',
errors: [],
parent: RequestError: Cannot insert duplicate key row in object 'dbo.Students' with unique index 'I_Name'. The duplicate key value is (John Doe).
有些错误消息可以通过
error.message
直接访问,有些则 AggregateErrors
嵌入在 error.parent
中。所以,这大致就是我的代码:
if (err instanceof UniqueConstraintError) {
// Send a generic conflict error
} else if (err instanceof ValidationError || err instanceof ForeignKeyConstraintError) {
// Send a generic invalid request error
} else if (err instanceof DatabaseError) {
// Send internal server error
}
这些响应消息不会透露导致这些错误的任何具体细节。这意味着如果有人将
firstName
留为空白,则响应应为 firstName cannot be null
。可能有 20-30 个字段和多个外键,并且仅提供类似于代码块的通用错误响应,使得用户交互效率非常低。
我早些时候就开始按照这个answer返回呼叫者。 但这并不能解决一些错误消息泄露数据库、表和/或约束的敏感信息的事实。
有没有更好/有效的方法来处理所有这些情况?
考虑定义扩展 JavaScript 错误类的自定义错误类。这些自定义错误类可以携带前端可以理解并向用户显示适当消息的特定错误代码或标识符。
class CustomError extends Error {
constructor(message, code) {
super(message)
this.name = this.constructor.name
this.code = code
}
}
处理 Sequelize 错误时,将它们映射到您的自定义错误类。这允许您抽象出特定于数据库的详细信息,同时向前端提供有意义的错误代码/消息。
function mapSequelizeError(err) {
if (err instanceof Sequelize.UniqueConstraintError) {
return new CustomError('Conflict: Duplicate entry', 'CONFLICT')
} else if (err instanceof Sequelize.ValidationError) {
// extract specific validation errors and construct a user-friendly message
const errors = err.errors.map(error => `${error.path} ${error.message}`)
return new CustomError(`Invalid request: ${errors.join(', ')}`, 'VALIDATION_ERROR')
} else if (err instanceof Sequelize.ForeignKeyConstraintError) {
return new CustomError('Invalid request: Foreign key constraint violated', 'FOREIGN_KEY_CONSTRAINT_ERROR')
} else {
return new CustomError('Internal server error', 'INTERNAL_SERVER_ERROR')
}
}
然后在 Express 应用程序中实现错误处理中间件,以在发送响应之前捕获错误并格式化错误。
app.use((err, req, res, next) => {
// map Sequelize errors to custom errors
const customError = mapSequelizeError(err)
// log the error for debugging purposes
console.error(err)
// send the appropriate response to the client
res.status(500).json({
error: {
message: customError.message,
code: customError.code
}
})
})
这样你的前端就可以检查API返回的错误对象的code属性来确定错误的类型并向用户显示相关消息。这种方法抽象了数据库特定的细节,同时向用户提供信息丰富的反馈。