在Mono/Flux错误处理器中获取请求链内requestId的技术问询
解决方案
针对你在Spring WebFlux中遇到的问题,这里有几个实用的方案可以在错误处理器中获取请求体的requestId,无需提前存入上下文或依赖自定义异常传递:
方案1:在flatMap内部处理异常(最直接)
既然已经在flatMap中拿到了解析后的MyRequest对象,直接在这个作用域内处理业务逻辑的异常,就能直接访问requestId。这种方式逻辑集中,不需要额外的上下文或缓存操作。
同步业务逻辑示例:
return request.bodyToMono(MyRequest.class) .flatMap(myRequest -> { try { // 执行同步业务逻辑 Object result = doSomeStuff(myRequest); return Mono.just(result); } catch (Exception e) { // 直接使用当前myRequest的requestId处理错误 return doSomeErrorHandling(e, myRequest.getRequestId()); } });
异步业务逻辑示例:
如果业务逻辑是异步的(返回Mono/Flux),直接在内部的onErrorResume中处理即可:
return request.bodyToMono(MyRequest.class) .flatMap(myRequest -> { // 执行异步业务逻辑 return doAsyncSomeStuff(myRequest) .onErrorResume(error -> { // 直接访问myRequest的requestId return doSomeErrorHandling(error, myRequest.getRequestId()); }); });
方案2:缓存请求体Mono,错误时复用
由于ServerRequest.bodyToMono()只能被订阅一次,我们可以用cache()操作符缓存解析后的请求体,这样在异常处理时可以再次订阅这个缓存的Mono获取requestId。
代码示例:
// 缓存请求体,避免重复解析 Mono<MyRequest> cachedRequest = request.bodyToMono(MyRequest.class).cache(); return cachedRequest .map(this::doSomeStuff) .onErrorResume(error -> { // 错误时从缓存的Mono中获取requestId return cachedRequest .map(MyRequest::getRequestId) .flatMap(requestId -> doSomeErrorHandling(error, requestId)); });
注意:如果请求体体积过大,缓存可能会占用较多内存,但一般业务场景下请求体不会过大,这个方案的适用性很强。
方案3:利用Reactor Context传递requestId
拿到请求体后,将requestId存入Reactor的Context中,后续的业务逻辑和异常处理都可以从Context中取出这个值,符合Reactor的响应式编程规范。
代码示例:
return request.bodyToMono(MyRequest.class) .flatMap(myRequest -> { // 将requestId写入Context return Mono.just(myRequest) .map(this::doSomeStuff) .contextWrite(ctx -> ctx.put("requestId", myRequest.getRequestId())); }) .onErrorResume(error -> { // 从Context中读取requestId return Mono.deferContextual(ctx -> { String requestId = ctx.get("requestId"); return doSomeErrorHandling(error, requestId); }); });
优点:适合在多个链式操作符之间共享requestId,如果后续还有其他需要用到requestId的操作,这种方式可以统一传递。
内容的提问来源于stack exchange,提问作者Corin Fletcher
相关产品推荐
相关产品推荐

