全局異常處理器詳解
什么是全局異常處理器?
全局異常處理器是Spring框架提供的統一異常處理機制,用于集中處理應用程序中所有控制器(Controller)層拋出的異常。它的核心價值在于:
- 統一異常處理:避免在每個Controller方法中重復編寫try-catch
- 標準化錯誤響應:確保所有異常返回一致的錯誤格式
- 解耦業務邏輯:將錯誤處理與業務代碼分離
- 提高可維護性:所有異常處理邏輯集中管理
- 增強安全性:防止敏感異常信息泄露給客戶端
核心實現方式
1. 使用 @ControllerAdvice
+ @ExceptionHandler
(推薦)
@RestControllerAdvice // 組合了@ControllerAdvice和@ResponseBody
public class GlobalExceptionHandler {// 處理自定義業務異常@ExceptionHandler(BusinessException.class)public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {ErrorResponse error = new ErrorResponse(ex.getErrorCode(),ex.getMessage(),System.currentTimeMillis());return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);}// 處理參數校驗異常@ExceptionHandler(MethodArgumentNotValidException.class)public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {List<String> errors = ex.getBindingResult().getFieldErrors().stream().map(error -> error.getField() + ": " + error.getDefaultMessage()).collect(Collectors.toList());ErrorResponse error = new ErrorResponse("VALIDATION_FAILED","參數校驗失敗",errors,System.currentTimeMillis());return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);}// 處理認證授權異常@ExceptionHandler(AccessDeniedException.class)public ResponseEntity<ErrorResponse> handleAccessDeniedException(AccessDeniedException ex) {ErrorResponse error = new ErrorResponse("UNAUTHORIZED","無訪問權限",System.currentTimeMillis());return new ResponseEntity<>(error, HttpStatus.FORBIDDEN);}// 處理所有未捕獲的異常@ExceptionHandler(Exception.class)public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {// 生產環境應隱藏詳細錯誤信息String message = "生產環境".equals(env) ? "服務器內部錯誤" : ex.getMessage();ErrorResponse error = new ErrorResponse("INTERNAL_SERVER_ERROR",message,System.currentTimeMillis());log.error("未處理異常: ", ex);return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);}
}
2. 錯誤響應體結構(標準化)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ErrorResponse {private String code; // 錯誤碼private String message; // 用戶友好消息private Object details; // 錯誤詳情(可選)private long timestamp; // 時間戳// 用于校驗錯誤的構造器public ErrorResponse(String code, String message, Object details, long timestamp) {this.code = code;this.message = message;this.details = details;this.timestamp = timestamp;}
}
企業級最佳實踐
1. 異常分類處理策略
異常類型 | HTTP狀態碼 | 處理方式 |
---|---|---|
業務邏輯異常 | 400 | 返回具體錯誤碼和用戶友好消息 |
參數校驗異常 | 400 | 返回具體字段錯誤信息 |
認證失敗異常 | 401 | 返回認證失敗提示 |
權限不足異常 | 403 | 返回權限不足提示 |
資源不存在異常 | 404 | 返回資源不存在提示 |
系統內部異常 | 500 | 返回通用錯誤(生產環境屏蔽細節) |
服務不可用異常 | 503 | 返回服務維護提示 |
2. 自定義業務異常體系
// 基礎業務異常
public class BusinessException extends RuntimeException {private final String errorCode;public BusinessException(String errorCode, String message) {super(message);this.errorCode = errorCode;}public String getErrorCode() {return errorCode;}
}// 具體業務異常
public class UserNotFoundException extends BusinessException {public UserNotFoundException(Long userId) {super("USER_NOT_FOUND", "用戶不存在: " + userId);}
}public class InsufficientBalanceException extends BusinessException {public InsufficientBalanceException(BigDecimal balance) {super("INSUFFICIENT_BALANCE", "余額不足,當前余額: " + balance);}
}
3. 自動處理參數校驗
結合 @Valid
注解自動捕獲校驗異常:
@PostMapping("/users")
public UserDTO createUser(@Valid @RequestBody CreateUserRequest request) {// 業務邏輯
}// 在全局異常處理器中
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {// 提取所有字段錯誤Map<String, String> errors = ex.getBindingResult().getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField,fieldError -> fieldError.getDefaultMessage() != null ? fieldError.getDefaultMessage() : ""));return ResponseEntity.badRequest().body(new ErrorResponse("VALIDATION_ERROR", "參數校驗失敗", errors));
}
4. 生產環境安全處理
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {// 區分開發和生產環境String errorMessage = "系統錯誤";// 開發環境顯示詳細錯誤if ("dev".equals(environment.getProperty("spring.profiles.active"))) {errorMessage = ex.getMessage();}// 記錄完整錯誤日志log.error("未處理異常: ", ex);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResponse("SERVER_ERROR", errorMessage));
}
高級功能擴展
1. 異常國際化支持
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex, HttpServletRequest request) {// 從請求頭獲取語言String language = request.getHeader("Accept-Language");Locale locale = StringUtils.hasText(language) ? Locale.forLanguageTag(language) : Locale.getDefault();// 使用MessageSource獲取本地化消息String localizedMessage = messageSource.getMessage(ex.getErrorCode(), new Object[]{}, ex.getMessage(), // 默認消息locale);return ResponseEntity.badRequest().body(new ErrorResponse(ex.getErrorCode(), localizedMessage));
}
2. 異常監控集成
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {// 發送異常到監控系統metricsService.recordException(ex);// 發送告警通知if (ex instanceof CriticalException) {alertService.sendCriticalAlert(ex);}// ... 其他處理
}
3. 自定義異常處理器順序
@Order(Ordered.HIGHEST_PRECEDENCE) // 最高優先級
@RestControllerAdvice
public class SecurityExceptionHandler {@ExceptionHandler(AuthenticationException.class)public ResponseEntity<ErrorResponse> handleAuthException(AuthenticationException ex) {// 特殊處理認證異常}
}@Order(Ordered.LOWEST_PRECEDENCE) // 最低優先級
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {// 兜底處理}
}
使用場景示例
Controller中的使用
@RestController
@RequestMapping("/api/orders")
public class OrderController {@PostMappingpublic ResponseEntity<OrderDTO> createOrder(@Valid @RequestBody CreateOrderRequest request) {// 業務代碼無需處理異常OrderDTO order = orderService.createOrder(request);return ResponseEntity.ok(order);}@GetMapping("/{id}")public ResponseEntity<OrderDTO> getOrder(@PathVariable Long id) {// 直接拋出業務異常OrderDTO order = orderService.getOrder(id).orElseThrow(() -> new OrderNotFoundException(id));return ResponseEntity.ok(order);}
}
最佳實踐總結
-
分層處理:
- 業務層拋出有含義的異常
- 控制器層不處理異常
- 全局處理器統一轉換異常為響應
-
標準化響應:
- 統一錯誤響應格式
- 包含錯誤碼、消息和時間戳
- 必要時添加錯誤詳情
-
異常分類:
- 為不同類型異常創建處理器
- 使用HTTP狀態碼合理映射業務異常
-
安全考慮:
- 生產環境屏蔽敏感異常信息
- 開發環境顯示詳細錯誤
-
監控集成:
- 記錄異常日志
- 集成監控告警系統
-
可擴展性:
- 使用自定義異常體系
- 支持異常國際化
全局異常處理器是構建健壯REST API的關鍵組件,它能顯著提高代碼質量、增強系統穩定性,并為客戶端提供一致的錯誤處理體驗。