Spring WebFlux函数式端点多异常处理方案咨询
Spring WebFlux函数式端点多异常处理实现方案
针对你提出的同一端点需根据不同异常返回不同响应的需求,提供两种对应注解控制器@ExceptionHandler效果的实现方式:
方式一:局部异常处理(推荐)
在业务处理的Mono流中使用onErrorResume方法捕获特定异常,直接在端点handler内完成自定义响应,符合函数式编程链式处理风格。
完整代码示例
1. 业务Handler实现
@Service public class UserHandler { private final UserService userService; public UserHandler(UserService userService) { this.userService = userService; } public Mono<ServerResponse> getUserById(ServerRequest request) { String userId = request.pathVariable("id"); return userService.findById(userId) // 正常业务逻辑:返回用户信息 .flatMap(user -> ServerResponse.ok().bodyValue(user)) // 捕获UserNotFoundException,返回404响应 .onErrorResume(UserNotFoundException.class, ex -> ServerResponse.status(HttpStatus.NOT_FOUND) .contentType(MediaType.APPLICATION_JSON) .bodyValue(Map.of( "errorCode", "USER_NOT_FOUND", "message", "用户ID:" + userId + "不存在", "timestamp", LocalDateTime.now().toString() )) ) // 捕获UserException,返回500响应 .onErrorResume(UserException.class, ex -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR) .contentType(MediaType.APPLICATION_JSON) .bodyValue(Map.of( "errorCode", "USER_SERVICE_ERROR", "message", "获取用户失败:" + ex.getMessage(), "timestamp", LocalDateTime.now().toString() )) ); } }
2. 路由配置
@Configuration public class UserRouter { @Bean public RouterFunction<ServerResponse> userRoutes(UserHandler userHandler) { return RouterFunctions.route( RequestPredicates.GET("/router/users/{id}") .and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), userHandler::getUserById ); } }
注意事项
- 异常捕获顺序:若异常存在继承关系(如
UserNotFoundException继承自UserException),必须将子类异常的onErrorResume放在父类前面,否则父类会优先捕获所有子类异常。 - 该方式仅作用于当前端点,不影响其他路由的异常处理逻辑。
方式二:全局异常处理
若需多个端点共享异常处理逻辑,可自定义ErrorWebExceptionHandler,结合请求路径和异常类型实现全局差异化处理。
完整代码示例
@Component public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler { public CustomErrorWebExceptionHandler(ErrorAttributes errorAttributes, WebProperties webProperties, ApplicationContext applicationContext, ServerCodecConfigurer serverCodecConfigurer) { super(errorAttributes, webProperties.getResources(), applicationContext); super.setMessageWriters(serverCodecConfigurer.getWriters()); super.setMessageReaders(serverCodecConfigurer.getReaders()); } @Override protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) { return RouterFunctions.route( // 针对指定端点的异常处理 RequestPredicates.path("/router/users/{id}"), request -> { Throwable error = getError(request); String userId = request.pathVariable("id"); if (error instanceof UserNotFoundException) { return ServerResponse.status(HttpStatus.NOT_FOUND) .contentType(MediaType.APPLICATION_JSON) .bodyValue(Map.of( "errorCode", "USER_NOT_FOUND", "message", "用户ID:" + userId + "不存在", "timestamp", LocalDateTime.now().toString() )); } else if (error instanceof UserException) { return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR) .contentType(MediaType.APPLICATION_JSON) .bodyValue(Map.of( "errorCode", "USER_SERVICE_ERROR", "message", "获取用户失败:" + error.getMessage(), "timestamp", LocalDateTime.now().toString() )); } // 其他异常走默认处理 return defaultErrorResponse(request, errorAttributes); } ).andRoute( // 其他所有端点的默认异常处理 RequestPredicates.all(), request -> defaultErrorResponse(request, errorAttributes) ); } // 全局默认错误响应 private Mono<ServerResponse> defaultErrorResponse(ServerRequest request, ErrorAttributes errorAttributes) { Map<String, Object> errorAttrs = getErrorAttributes(request, ErrorAttributeOptions.defaults()); return ServerResponse.status((HttpStatus) errorAttrs.get("status")) .contentType(MediaType.APPLICATION_JSON) .bodyValue(errorAttrs); } }
适用场景
- 多个端点需相同异常处理逻辑,避免重复代码。
- 需要统一管理所有异常的响应格式。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

