阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 错误响应标准化处理

错误响应标准化处理

作者:陈川 阅读数:48609人阅读 分类: Node.js

错误响应标准化处理

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

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌