后端校验与异常处理规范
校验与异常处理规范
适用场景
修改构造参数、入口参数、外部结果校验、错误码、异常或人工审核原因时加载。
基本分类
区分调用契约错误和业务数据异常:
- 调用契约错误不能形成可信决策,使用
IllegalArgumentException快速失败。 - 供应商或事件数据异常属于需要解释的业务事实,不抛异常,返回
MANUAL_REVIEW。
调用契约错误
以下情况抛 IllegalArgumentException,错误消息指出具体参数:
order、result或now为null。orderId为空、updatedAt为空、订单状态为空或reconciliationAttempts < 0。CreateAttemptResult.outcome为空。maxQueryAttempts <= 0、retryDelay == null或retryDelay为负数。
业务数据异常
- 空字符串和仅空白字符串都按字段缺失处理。
- 事件缺少
eventId、clientReference或occurredAt:MANUAL_REVIEW/INVALID_EVENT_DATA。 - 事件或匹配记录的
clientReference与orderId不同:MANUAL_REVIEW/CLIENT_REFERENCE_MISMATCH。 - 匹配记录缺少
supplierBookingId或状态:MANUAL_REVIEW/INVALID_EVENT_DATA。 CONFIRMED缺少confirmationCode:MANUAL_REVIEW/CONFIRMED_RESULT_INCOMPLETE;其他供应商状态不强制要求确认号。- 查询同时返回一个匹配和
errorCode:MANUAL_REVIEW/QUERY_RESULT_CONFLICT。 - 查询返回多个匹配时始终优先
MULTIPLE_SUPPLIER_BOOKINGS,即使同时带有errorCode。
禁止做法
- 不捕获或吞掉
RuntimeException,不返回伪造的成功决策。 - 不使用异常推动正常业务状态流转,不创建自定义异常层级。
- 不用空值默认成成功、失败或“供应商未建单”。
Spring MVC 边界
- Controller 请求 DTO 使用
@Valid和 Jakarta Bean Validation 完成格式、长度、必填项等信任边界校验;领域服务继续校验业务不变量。 - 使用单个
@RestControllerAdvice统一映射 HTTP 错误,不在每个 Controller 复制try/catch。 - 参数绑定或校验失败返回
400;找不到资源返回404;状态冲突返回409;未分类异常返回500,不得向客户端暴露堆栈、类名、SQL 或供应商敏感信息。 - 错误响应至少包含稳定
code、可读message和当前请求的traceId;同一错误的 HTTP 响应、日志和审计记录必须使用同一traceId。 IllegalArgumentException只有在明确代表客户端输入或调用契约错误时映射为400;其他意外运行时异常不得伪装成客户端错误。- traceId 不从请求体或业务参数读取,统一按
07-spring-mvc-traceid.md从请求上下文取得。