SpringBoot通用异常处理:微服务场景下的最佳实践
·
Spring Boot通用异常处理:微服务场景下的最佳实践
在微服务架构中,统一的异常处理至关重要。它能保证各服务返回一致的错误格式,便于客户端处理和日志监控。以下是Spring Boot的通用异常处理最佳实践:
1. 统一响应格式
定义标准错误响应体,包含错误码、消息和详情:
public class ErrorResponse {
private int status; // HTTP状态码
private String code; // 业务错误码
private String message; // 用户友好消息
private String detail; // 调试详情(仅开发环境)
// 构造方法/getter/setter
}
2. 全局异常处理器
使用@RestControllerAdvice创建全局异常处理器:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex, WebRequest request) {
ErrorResponse error = new ErrorResponse(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"SYSTEM_ERROR",
"服务暂时不可用",
ex.getMessage()
);
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
3. 分层异常处理策略
按异常类型分层处理:
HTTP异常处理
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
protected ResponseEntity<ErrorResponse> handleMethodNotSupported() {
ErrorResponse error = new ErrorResponse(405, "METHOD_NOT_ALLOWED", "不支持的HTTP方法");
return ResponseEntity.status(405).body(error);
}
业务异常处理
// 自定义业务异常
public class BusinessException extends RuntimeException {
private final String errorCode;
// 构造方法
}
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {
ErrorResponse error = new ErrorResponse(400, ex.getErrorCode(), ex.getMessage());
return ResponseEntity.badRequest().body(error);
}
参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {
String errorMsg = ex.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining("; "));
ErrorResponse error = new ErrorResponse(400, "INVALID_PARAM", "参数校验失败", errorMsg);
return ResponseEntity.badRequest().body(error);
}
4. 微服务特殊处理
Feign客户端异常传递
@ExceptionHandler(FeignException.class)
public ResponseEntity<ErrorResponse> handleFeignException(FeignException ex) {
// 解析上游服务返回的错误
if(ex.status() >= 400) {
ErrorResponse upstreamError = parseError(ex.contentUTF8());
return ResponseEntity.status(ex.status()).body(upstreamError);
}
return handleAll(ex, null);
}
熔断降级异常
// Hystrix降级方法
public ErrorResponse fallbackMethod(Throwable ex) {
return new ErrorResponse(503, "SERVICE_UNAVAILABLE", "服务暂时降级");
}
5. 最佳实践建议
-
错误码规范:
- 使用分级错误码:
[服务标识].[模块].[具体错误](如USER.AUTH.PASSWORD_INVALID) - 预定义错误码枚举类
- 使用分级错误码:
-
环境差异化处理:
@Value("${spring.profiles.active}") private String activeProfile; if("prod".equals(activeProfile)) { error.setDetail(null); // 生产环境隐藏堆栈 } -
异常日志记录:
@ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleAll(Exception ex) { log.error("全局异常: {}", ex.getMessage(), ex); // 完整日志 // ...返回简化错误 } -
HTTP状态码映射:
异常类型 HTTP状态码 身份验证异常 401 权限不足 403 资源不存在 404 业务参数错误 400 依赖服务不可用 502
6. 完整配置示例
@RestControllerAdvice
public class GlobalExceptionHandler {
private final String activeProfile;
public GlobalExceptionHandler(@Value("${spring.profiles.active:dev}") String activeProfile) {
this.activeProfile = activeProfile;
}
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusiness(BusinessException ex) {
return ResponseEntity.badRequest().body(
buildError(400, ex.getCode(), ex.getMessage())
);
}
@ExceptionHandler(FeignException.class)
public ResponseEntity<ErrorResponse> handleFeign(FeignException ex) {
if(ex.status() >= 400) {
return ResponseEntity.status(ex.status())
.body(parseFeignError(ex));
}
return handleRuntime(new RuntimeException("服务调用异常", ex));
}
private ErrorResponse buildError(int status, String code, String message) {
return new ErrorResponse(status, code, message,
"dev".equals(activeProfile) ? getStackTrace() : null
);
}
}
关键优势
- 统一格式:所有服务返回相同结构的错误响应
- 错误隔离:框架异常与业务异常分离处理
- 安全控制:生产环境隐藏敏感错误详情
- 链路追踪:通过错误码快速定位问题服务
- 客户端友好:提供可国际化的用户友好消息
重要提示:在微服务架构中,建议将异常处理器封装为公共starter包,确保所有服务遵循相同的异常处理规范。
更多推荐
所有评论(0)