createReactiveErrorManager
后端业务错误码管理系统,支持国际化和分类管理。
函数签名
typescript
function createReactiveErrorManager(
config: ErrorManagerConfig,
deps: ErrorManagerDeps
): ErrorManagerInstance
interface ErrorManagerConfig {
defaultLocale: string
fallbackLocale?: string
categories: ErrorCategory[]
}
interface ErrorCategory {
name: string
prefix: string
errors: ErrorCode[]
}
interface ErrorCode {
code: string
message: Record<string, string>
httpStatus?: number
level?: 'info' | 'warning' | 'error' | 'fatal'
metadata?: Record<string, any>
}
class BusinessError extends Error {
code: string
httpStatus: number
level: 'info' | 'warning' | 'error' | 'fatal'
metadata: Record<string, any>
params?: Record<string, any>
}参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
config | ErrorManagerConfig | 是 | 错误管理器配置 |
config.defaultLocale | string | 是 | 默认语言 |
config.fallbackLocale | string | 否 | 回退语言 |
config.categories | ErrorCategory[] | 是 | 错误分类列表 |
deps | ErrorManagerDeps | 是 | 环境依赖 |
返回值
| 类型 | 说明 |
|---|---|
ErrorManagerInstance | 错误管理器实例 |
工作原理
- 分类管理:按模块组织错误码(USER、ORDER、SYS等)
- 国际化:每个错误码支持多语言消息
- 参数化:支持
{key}格式的参数替换 - 错误创建:提供 BusinessError 类封装错误信息
- 响应式:语言切换时自动更新
基础示例
typescript
import { createReactiveErrorManager } from 'zcw-shared/reactive/createReactiveErrorManager'
import { createReactive } from 'zcw-shared/reactive/createReactive'
const errorManager = createReactiveErrorManager({
defaultLocale: 'zh-CN',
fallbackLocale: 'en',
categories: [
{
name: '用户相关',
prefix: 'USER',
errors: [
{
code: 'USER_NOT_FOUND',
message: {
'zh-CN': '用户不存在',
'en': 'User not found'
},
httpStatus: 404,
level: 'error'
},
{
code: 'USER_ALREADY_EXISTS',
message: {
'zh-CN': '用户 {username} 已存在',
'en': 'User {username} already exists'
},
httpStatus: 409
}
]
}
]
}, {
createReactive,
log: console.log,
warn: console.warn
})
// 获取错误消息
const msg = errorManager.getMessage('USER_NOT_FOUND')
console.log(msg) // '用户不存在'
// 带参数的消息
const msg2 = errorManager.getMessage('USER_ALREADY_EXISTS', { username: 'alice' })
console.log(msg2) // '用户 alice 已存在'
// 创建错误
const error = errorManager.createError('USER_NOT_FOUND')
console.log(error instanceof BusinessError) // true
console.log(error.code) // 'USER_NOT_FOUND'
console.log(error.httpStatus) // 404
// 抛出错误
try {
errorManager.throwError('USER_NOT_FOUND')
} catch (e) {
if (e instanceof BusinessError) {
console.log(e.code, e.message, e.httpStatus)
}
}实际应用场景
Express/Koa 中间件
typescript
// 错误处理中间件
app.use((err, req, res, next) => {
if (err instanceof BusinessError) {
res.status(err.httpStatus).json({
success: false,
code: err.code,
message: err.message,
data: null
})
} else {
res.status(500).json({
success: false,
code: 'SYS_INTERNAL_ERROR',
message: '系统内部错误',
data: null
})
}
})
// 使用示例
app.post('/api/users', async (req, res, next) => {
try {
const { username } = req.body
const exists = await checkUserExists(username)
if (exists) {
errorManager.throwError('USER_ALREADY_EXISTS', { username })
}
// ...创建用户
} catch (err) {
next(err)
}
})微服务错误处理
typescript
// 定义错误码常量
export const ErrorCodes = {
USER_NOT_FOUND: 'USER_NOT_FOUND',
USER_UNAUTHORIZED: 'USER_UNAUTHORIZED',
ORDER_NOT_FOUND: 'ORDER_NOT_FOUND'
} as const
// 在服务中使用
class UserService {
async getUser(userId: string) {
const user = await this.db.findUser(userId)
if (!user) {
throw errorManager.createError(ErrorCodes.USER_NOT_FOUND)
}
return user
}
}API 响应封装
typescript
interface ApiResponse<T = any> {
success: boolean
code: string
message: string
data: T | null
}
function successResponse<T>(data: T): ApiResponse<T> {
return {
success: true,
code: 'SUCCESS',
message: '操作成功',
data
}
}
function errorResponse(error: BusinessError): ApiResponse {
return {
success: false,
code: error.code,
message: error.message,
data: null
}
}国际化支持
typescript
// 根据请求头切换语言
app.use((req, res, next) => {
const locale = req.headers['accept-language']?.split(',')[0] || 'zh-CN'
errorManager.setLocale(locale)
next()
})
// 返回对应语言的错误消息
app.post('/api/login', (req, res) => {
if (!validPassword) {
const error = errorManager.createError('INVALID_PASSWORD', { minLength: 8 })
return res.status(error.httpStatus).json(errorResponse(error))
}
})最佳实践
1. 错误码命名规范
typescript
// 格式:{模块前缀}_{描述}
USER_NOT_FOUND // 用户模块
ORDER_CANCELLED // 订单模块
SYS_INTERNAL_ERROR // 系统模块
PAYMENT_FAILED // 支付模块2. 按模块组织
typescript
const categories = [
{ name: '用户模块', prefix: 'USER', errors: [...] },
{ name: '订单模块', prefix: 'ORDER', errors: [...] },
{ name: '支付模块', prefix: 'PAYMENT', errors: [...] },
{ name: '系统模块', prefix: 'SYS', errors: [...] }
]3. HTTP 状态码映射
typescript
// 400 系列 - 客户端错误
{ code: 'INVALID_PARAMS', httpStatus: 400 }
{ code: 'USER_UNAUTHORIZED', httpStatus: 401 }
{ code: 'ACCESS_DENIED', httpStatus: 403 }
{ code: 'USER_NOT_FOUND', httpStatus: 404 }
{ code: 'USER_ALREADY_EXISTS', httpStatus: 409 }
// 500 系列 - 服务端错误
{ code: 'SYS_INTERNAL_ERROR', httpStatus: 500 }
{ code: 'SYS_SERVICE_UNAVAILABLE', httpStatus: 503 }4. 错误级别使用
typescript
level: 'info' // 信息,如订单已取消
level: 'warning' // 警告,如库存不足
level: 'error' // 错误,如用户不存在
level: 'fatal' // 严重,如系统崩溃统一的业务错误码管理,让后端开发更规范!