错误响应标准化处理
错误响应标准化处理
Koa2应用中错误处理是核心环节之一。统一的错误响应格式能提升API可维护性,前端开发者能快速定位问题。错误标准化包含状态码规范、数据结构定义和错误分类处理。
错误响应基础结构
标准错误响应应包含三个基本字段:
{
"code": 400001,
"message": "参数校验失败",
"data": {
"detail": "用户名不能为空"
}
}
code
: 业务自定义错误码,通常6位数字,前三位表示错误大类message
: 人类可读的错误描述data
: 可选字段,存放错误详情或调试信息
错误分类处理方案
HTTP标准错误
直接复用HTTP状态码体系:
ctx.status = 404;
ctx.body = {
code: 404000,
message: '资源不存在'
}
业务逻辑错误
自定义错误码范围(示例):
// 用户相关错误 400100-400199
const USER_ERRORS = {
INVALID_CREDENTIALS: [400101, '用户名或密码错误'],
DUPLICATE_EMAIL: [400102, '邮箱已被注册']
}
throw new BusinessError(USER_ERRORS.INVALID_CREDENTIALS);
系统级错误
5xx错误应当记录日志但不暴露细节:
app.on('error', (err, ctx) => {
logger.error('server error', err);
ctx.status = 500;
ctx.body = {
code: 500000,
message: '系统繁忙,请稍后重试'
}
});
实现中间件方案
创建错误处理中间件:
async function errorHandler(ctx, next) {
try {
await next();
} catch (err) {
// 已知业务错误
if (err instanceof BusinessError) {
ctx.status = 400;
ctx.body = {
code: err.code,
message: err.message,
data: err.data
};
return;
}
// 参数校验错误
if (err instanceof ParameterError) {
ctx.status = 422;
ctx.body = {
code: 422000,
message: '参数校验失败',
data: err.errors
};
return;
}
// 未知系统错误
ctx.app.emit('error', err, ctx);
}
}
错误码规范设计
采用分层编码方案:
400000
├─ 400100 用户模块错误
│ ├─ 400101 认证失败
│ └─ 400102 权限不足
└─ 400200 订单模块错误
├─ 400201 库存不足
└─ 400202 支付超时
维护错误码常量文件:
// error-codes.js
module.exports = {
USER: {
AUTH_FAILED: [400101, '认证失败'],
PERMISSION_DENIED: [400102, '权限不足']
},
ORDER: {
OUT_OF_STOCK: [400201, '库存不足'],
PAYMENT_TIMEOUT: [400202, '支付超时']
}
}
参数校验错误处理
使用Joi校验时的错误转换:
const schema = Joi.object({
username: Joi.string().required(),
age: Joi.number().min(18)
});
async function validate(ctx, next) {
try {
const { error, value } = schema.validate(ctx.request.body);
if (error) {
throw new ParameterError('参数不合法', error.details);
}
ctx.validatedData = value;
await next();
} catch (err) {
throw err;
}
}
输出格式示例:
{
"code": 422000,
"message": "参数校验失败",
"data": [
{
"path": ["username"],
"message": "用户名不能为空"
},
{
"path": ["age"],
"message": "年龄必须大于18岁"
}
]
}
多语言错误消息
支持动态消息国际化:
class I18nError extends Error {
constructor(key, data) {
const message = i18n.t(key, data);
super(message);
this.key = key;
this.data = data;
}
}
// 使用示例
throw new I18nError('errors.user.not_found', { userId: 123 });
错误日志记录策略
开发环境记录完整堆栈:
if (process.env.NODE_ENV === 'development') {
ctx.body.stack = err.stack;
}
生产环境日志规范:
logger.error({
type: 'API_ERROR',
code: err.code,
path: ctx.path,
params: ctx.request.body,
stack: err.stack
});
客户端错误处理示例
前端处理标准化错误响应:
async function fetchData() {
try {
const res = await axios.get('/api/user');
return res.data;
} catch (err) {
if (err.response) {
const { code, message } = err.response.data;
switch(code) {
case 400101:
showToast(message);
redirectToLogin();
break;
case 500000:
showSystemErrorDialog();
break;
default:
handleCommonError(message);
}
}
}
}
测试阶段的错误模拟
单元测试中模拟错误响应:
describe('Error Handling', () => {
it('should return 400 for invalid params', async () => {
const res = await request(app)
.post('/login')
.send({});
expect(res.status).toBe(400);
expect(res.body.code).toBe(400101);
});
});
Mock服务示例:
nock('https://api.example.com')
.get('/users/1')
.reply(500, {
code: 500001,
message: '数据库连接超时'
});
性能监控集成
错误指标上报:
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
metrics.increment('api.error', {
code: err.code,
path: ctx.path
});
throw err;
}
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:响应压缩与性能优化
下一篇:MySQL 数据库连接与操作