• WebFlux异常处理:onErrorReturn和onErrorResume


    1 缘起

    最近在学习WebFlux
    处理异常时遇到些问题,比如,Java直接抛出的异常无法直接被onErrorReturn和onErrorResume捕获,
    但是,在map或者flatMap等方法之后的异常又可以直接被捕获,
    于是,进行了测试,发现,onErrorReturn和onErrorResume可以捕获的异常是Throwable类型或者Mono或Flux包装的类型。
    当我们在使用WebFlux中的onErrorReturn和onErrorResume捕获异常时,有两种方式:
    (1)当原生Java运行时异常抛出时,需要使用Mono或Flux包装:Mono.error或FluxError;
    (2)在map或者flatMap等其他原生方法中抛出的异常可以直接被捕获,无需包装。
    特分享如下,帮助读者轻松应对知识交流与考核。
    在这里插入图片描述

    2 异常处理

    异常处理是软件开发中非常重要的一环,
    在业务系统中,我们需要捕获异常,给出合适的描述信息,让调用者清晰这是哪一个环节的异常。
    在计算相关的业务中,通常对计算结果有更多的要求,比如,程序内部出现异常后,不能影响计算结果的输出,需要有一个保底的计算结果,比如在广告推荐系统中的广告出价,即使程序内部出现异常,仍要返回最终的广告出价,保证流程可以正常继续往下走。
    当然,不同的业务系统有不同的需求,有的需要直接将异常暴露出去,有的需要记录但是给出保底的结果,但是,都要都要对异常进行处理。

    2.1 WebFlux异常处理

    WebFlux中的异常处理与SpringMVC中的异常处理存在不同的地方,
    相同:都可使用全局异常拦截;
    不同:WebFlux可以使用自定义的异常处理方法,如onErrorReturn和onErrorResume。
    在WebFlux中,onErrorReturn和onErrorResume可以处理的异常是经过Mono或Flux包装的。
    可以这样理解:Java直接抛出的运行时异常,onErrorReturn和onErrorResume无法直接捕获,需要通过Mono.error或者Flux.error包装,才能被正常捕获,当然,如果启用了全局异常捕获,则无需包装。
    下面看一下onErrorReturn和onErrorResume的源码:

    onErrorReturn

    在这里插入图片描述

    onErrorReusme

    在这里插入图片描述

    由源码可知,onErrorReturn中调用了onErrorResume,不同的是入参和返回值,onErrorReturn入参是固定值,onErrorResume入参是函数,可以自定义处理逻辑。onErrorResume的参数为Functions,由这个泛型参数可知,onErrorResume只能处理Throwable类型和Mono及其子类的类型数据,所以,无法直接捕获Java原生运行时异常。Java可抛出异常是Error和Exception的父类,因此,任何运行时异常都不能被onErrorResume或者onErrorReturn捕获,除非使用Mono.error或者Flux.error包装起来,才能正常捕获。
    Java异常关系:https://blog.csdn.net/Xin_101/article/details/110210485

    2.2 样例

    前提条件:未开启全局异常捕获

    • 接口
    @GetMapping("/mathematics/operation/flow/mono")
        @ApiOperation("连续流测试mono")
        public Mono<Response<Integer>> mathematicsOperationFlowUnderMono(@RequestParam Integer var1, @RequestParam Integer var2) {
    
            return mathematicsOperationService.divideMono(var1, var2)
                    .onErrorReturn(10)
                    .map(addResult -> {
                        logger.info(">>>>>>Add result:{}", addResult);
                        return Response.success(addResult);
                    })
                    .onErrorResume(ex -> {
                        logger.info(">>>>>>Error resume:", ex);
                        return Mono.just(Response.fail(-100));
                    });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.2.1 原生运行时异常

    Java原生异常即Throwable子类的错误和异常:Error和Exception。
    以运行时异常为例,当程序出现异常时,接口返回的结果是WebFlux的信息,而不是开发者自定义的响应模板。

    • 异常处理
        @Override
        public Mono<Integer> divideMono(Integer var1, Integer var2) {
            try{
                return Mono.just(var1 / var2);
            } catch(Exception ex) {
                throw new RuntimeException("自定义运行时异常");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    返回的信息如下:
    在这里插入图片描述

    2.2.2 Mono包装异常

    onErrorReturn和onErrorResume可以处理Mono或Flux包装的异常,
    包装如下:

    • 异常处理
        @Override
        public Mono<Integer> divideMono(Integer var1, Integer var2) {
            try{
                return Mono.just(var1 / var2);
            } catch(Exception ex) {
                return Mono.error(ex);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    包装后的异常可以被哦那Error Return捕获,接口中在onErrorReturn中使用了固定数值:10,因此返回的结果是10,结果如下:
    在这里插入图片描述

    2.2.3 原生Mono异常

    由上面可知,WebFlux可以捕获处理Mono或Flux包装的异常信息,
    因此,当我们使用map或者flatMap处理数据时,可以直接使用onErrorReturn和onErrorResume捕获异常,map和flatMap中产生的异常会被直接捕获,无需进行包装。
    为了测试,我们在map中添加了1/0,运行时会抛出异常,然后在onErrorResume中捕获异常,并返回-100。

        @GetMapping("/mathematics/operation/flow/mono")
        @ApiOperation("连续流测试mono")
        public Mono<Response<Integer>> mathematicsOperationFlowUnderMono(@RequestParam Integer var1, @RequestParam Integer var2) {
    
            return mathematicsOperationService.divideMono(var1, var2)
                    .onErrorReturn(10)
                    .onErrorResume(ex -> {
                        logger.info(">>>>>>Error resume -1:", ex);
                        return Mono.just(-1);})
                    .map(addResult -> {
                        logger.info(">>>>>>Add result:{}", addResult);
                        int a = 1/0;
                        return Response.success(addResult);
                    })
                    .onErrorResume(ex -> {
                        logger.info(">>>>>>Error resume:", ex);
                        return Mono.just(Response.fail(-100));
                    });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    当出现异常时,onErrorResume会直接捕获,并返回自定义的数据,如上面的-100,
    结果如下图所示。

    在这里插入图片描述

    3 小结

    (1)WebFlux处理异常可以使用onErrorReturn和onErrorResume;
    (2)onErrorReturn和onErrorResume可以处理的异常是Throwable类型以及Mono或者Flux及其子类包装的异常;
    (3)使用Mono.error和Flux.error包装异常或者在map,flatMap之后处理异常。

  • 相关阅读:
    c++ 模板详解
    熵、信息增益----决策树原理分析、代码实现与绘图
    Python实战项目:消消乐(源码分享)(文章较短,直接上代码)
    优思学院|精益六西格玛中的8大浪费是什么?
    聊聊数据库建表的15个小技巧
    【生活】如何学习理财
    pdf加水印方法,快速给pdf加水印
    ​​​​MyBatis友人帐之基础入门
    Web3 招聘 | Bitget、MyShell、imToken、Arweave 多项目招聘中
    【Kotlin】初识Kotlin(二)
  • 原文地址:https://blog.csdn.net/Xin_101/article/details/132941786