为Mono添加调用信息以优化REST服务异常处理
为Mono异常添加API路径信息的解决方案
问题背景
我们通过Spring WebFlux的Mono处理REST服务调用,当前已通过addTimeoutAndRetryToMono方法为Mono添加超时、重试和错误映射逻辑,但抛出的异常(如TimeoutException)缺少被调用服务的路径信息。路径仅在OpenAPI生成的getMonoForServiceCall方法中可用,直接传递路径因方法数量多不够优雅,尝试用contextWrite存入上下文但未在错误映射中成功获取。需在getMonoForServiceCall和addTimeoutAndRetryToMono层面修改,且getMonoForServiceCall需保持返回Mono<T>。
核心解决方案
利用Reactor的上下文(Context)存储API路径,在错误处理时读取上下文信息生成带路径的自定义异常。关键是使用onErrorMap的重载方法,该方法可同时接收异常和上下文视图(ContextView)。
修改后的代码实现
1. 在getMonoForServiceCall中存入路径到上下文
Mono<T> getMonoForServiceCall(Object param) { // ... 原有逻辑:准备请求参数、确定API路径等 String apiPath = "..."; // 实际生成的API路径 WebClient.RequestBodySpec requestBuilder = prepareRequest(webClient, apiPath, param); // 将路径存入Mono上下文 return requestBuilder.retrieve().bodyToMono(returnType) .contextWrite(ctx -> ctx.put("api-path", apiPath)); }
2. 修改addTimeoutAndRetryToMono读取上下文并处理异常
Mono<T> addTimeoutAndRetryToMono(Mono<T> mono) { return mono.timeout(Duration.ofSeconds(10)) // 使用带ContextView的onErrorMap重载方法 .onErrorMap((throwable, contextView) -> { String path = contextView.getOrDefault("api-path", "未知路径"); return handleExceptions(throwable, path); }); } Throwable handleExceptions(Throwable t, String path) { // 根据异常类型生成带路径的自定义消息 if (t instanceof TimeoutException) { return new RestClientException(String.format("调用%s时超时", path), t); } return new RestClientException(String.format("调用%s时出错:%s", path, t.getMessage()), t); }
说明
- 上下文(Context)是Reactor中用于传递跨操作元数据的机制,
contextWrite方法会将键值对存入当前Mono的上下文,后续操作可通过ContextView读取。 - 使用
getOrDefault避免因上下文未包含路径导致的异常,默认使用"未知路径"作为兜底。 - 异常处理时保留原始异常作为cause,便于排查根因。
内容的提问来源于stack exchange,提问作者Andrei
相关产品推荐
相关产品推荐

