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. 最佳实践建议
  1. 错误码规范

    • 使用分级错误码:[服务标识].[模块].[具体错误](如USER.AUTH.PASSWORD_INVALID
    • 预定义错误码枚举类
  2. 环境差异化处理

    @Value("${spring.profiles.active}")
    private String activeProfile;
    
    if("prod".equals(activeProfile)) {
        error.setDetail(null); // 生产环境隐藏堆栈
    }
    

  3. 异常日志记录

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
        log.error("全局异常: {}", ex.getMessage(), ex); // 完整日志
        // ...返回简化错误
    }
    

  4. 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
        );
    }
}

关键优势
  1. 统一格式:所有服务返回相同结构的错误响应
  2. 错误隔离:框架异常与业务异常分离处理
  3. 安全控制:生产环境隐藏敏感错误详情
  4. 链路追踪:通过错误码快速定位问题服务
  5. 客户端友好:提供可国际化的用户友好消息

重要提示:在微服务架构中,建议将异常处理器封装为公共starter包,确保所有服务遵循相同的异常处理规范。

更多推荐