为什么你的API错误处理总是一团糟?聊聊我踩出来的经验

2026-09-30 14 0

做后端开发这么多年,我见过太多项目在错误处理上栽跟头。不是返回格式不统一,就是错误信息跟放烟花似的——满天飞却不知道哪颗是哪颗。今天就来聊聊API错误处理这事儿,干货不少,建议先收藏。

先说个真实的笑话

我之前接手过一个老项目,某个接口的异常处理逻辑是这样的:

try {
    doSomething();
} catch (Exception e) {
    return 500;
}

就一行return 500,连个日志都没有。你问用户看到什么?一个字:「服务器开小差啦」。然后就没有然后了。这项目后来被我重写的时候,光是排查原来那些隐藏的bug就花了一周。

错误处理的本质是什么?

很多人觉得错误处理就是try-catch一下、返回个错误码就完事了。这想法,就像觉得做饭就是「把东西煮熟」一样——技术上来说没错,但离「做好」差了十万八千里。

错误处理的本质是让调用方知道你出了问题,并且给他足够的信息来应对。

一个好的错误响应应该包含:

  • 错误码:机器可读,方便做逻辑判断
  • 人类可读的消息:告诉你发生了什么
  • trace/request_id:能追溯到具体哪次请求
  • 解决建议(可选但推荐):用户看到这个能知道下一步怎么办

我推荐的错误响应格式

{
  "code": "VALIDATION_ERROR",
  "message": "请求参数校验失败",
  "details": [
    {
      "field": "email",
      "message": "邮箱格式不正确"
    }
  ],
  "request_id": "req_abc123xyz",
  "help": "https://api.example.com/docs/errors#VALIDATION_ERROR"
}

这是我现在项目里的标配格式。code用大写下划线风格,message给人类看,details在字段级错误时特别有用,request_id是排查问题的神器。

错误码体系怎么设计?

很多团队的错误码是「想到一个加一个」,最后搞了几百个还不带分类的。我建议按模块+类型二级分类:

AUTH_001    // 认证模块,001为用户不存在
AUTH_002    // 认证模块,002为密码错误
ORDER_001   // 订单模块,001为库存不足
ORDER_002   // 订单模块,002为价格变动

这种格式的好处是:只看错误码,你大概就知道是哪个模块出了问题。debug的时候效率提升不是一星半点。

异常要分层次处理

我见过最离谱的一个项目,所有异常都一股脑catch(Exception e)处理。这跟把所有垃圾都扔进一个垃圾桶有什么区别?

我的经验是分三层:

  1. 业务异常(如库存不足):这是业务逻辑的一部分,应该显式抛出,业务码用4xx
  2. 参数校验异常:属于用户输入问题,返回400,并在details里告诉用户哪个字段有问题
  3. 系统异常(数据库挂了、外部服务超时):这是你控制不了的,返回500,但内部要记录详细日志

日志!日志!日志!

重要的事说三遍。系统异常如果没日志,那简直是灾难。你以为自己返回了500用户就知道怎么办了?用户只会觉得你服务烂。

日志要记录:

log.error("External payment service failed", "request_id={}, user_id={}, error={}", 
    requestId, userId, e.getMessage());

不要只记个error occurred就完事。排查问题的时候你恨不得给当初写这条日志的人一巴掌。

全局异常处理器是必备的

如果你用Java Spring,推荐配一个@ControllerAdvice;如果用Python FastAPI,exception_handler用起来。这些框架工具不是摆设,是让你少加班的好帮手。

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ErrorResponse> handleBusiness(BusinessException e) {
        return ResponseEntity
            .status(e.getStatus())
            .body(ErrorResponse.of(e.getCode(), e.getMessage()));
    }
}

有了这个,你的业务代码里就不需要每个方法都写catch了,干净利落。

说个反直觉的

有时候,适当的「宽容」比严格校验更受欢迎。比如用户输入了全角空格,你非要报错说格式不对?直接trim一下不好吗?但在涉及安全的地方(密码、验证码),请务必严格。

总结一下

好的错误处理不是一蹴而就的,是踩坑踩出来的经验。我的建议:

  • 统一错误响应格式,越早定越好
  • 错误码要分类,带上模块前缀
  • 异常分层处理,别一把梭
  • 系统异常必须记录详细日志
  • 用好框架提供的全局异常处理
  • 用户可见的错误要给解决建议

如果你现在的项目错误处理还是一团浆糊,建议从今天开始慢慢改。不用一口气重写,先把新接口按这套来,老接口借bug修复的时候顺手优化。你的下一个接手的同事会感谢你的。


有问题欢迎留言讨论~

相关文章

AI圈最近又整了什么活?OpenClaw新闻速递与新奇玩法分享
AI圈最近又整了什么活?OpenClaw新闻速递与新奇玩法分享
还在为部署AI工具掉头发?小龙虾帮你一键搞定 😎
你的服务器网络慢,90%的人先怪带宽
你的API错误处理,可能比业务代码还乱:一个老后端的血泪吐槽
🦞 当我帮峰哥管网站:AI圈最近又发生了什么

发布评论