提问者:小点点

Spring Cloud Gateway链接嵌套Mono


我有一个Web应用程序(带有项目Reactor的Spring Cloud Gateway),当出现问题时,我必须注销(发送另一个超文本传输协议请求),并将401设置为主响应。问题是当我在onErrorResume块中执行另一个请求时,根响应似乎完全忽略了finish与状态()逻辑并返回200。

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return  someFunctionWhichReturnsMono()
                .flatMap(chain::filter)
                .onErrorResume(e -> {
                    log.error("Unexpected Filter Error, logging out user", e);

                    // A. this doesn't set 401, seems like ignoring finishWithStatus(..) 
                    // called inside this method in onErrorResume block
                    return logout(exchange);  

                    // B. this works fine and I get 401 as a response
                    // return finishWithStatus(exchange, HttpStatus.UNAUTHORIZED);
                });
    }

    protected Mono<Void> finishWithStatus(ServerWebExchange exchange, HttpStatus status) {
        exchange.getResponse().setStatusCode(status);
        return exchange.getResponse().setComplete();
    }

    protected void logout(ServerWebExchange exchange) {
        webClient
                .post()
                .uri(....)
                .retrieve()
                .bodyToMono(Void.class)
                .doOnSuccess(any -> {
                    log.info("Successfully logged out user");
                })
                .then(finishWithStatus(exchange, HttpStatus.UNAUTHORIZED))
                .onErrorResume(e -> {
                    log.error("Failed to logout user", e);
                    //the following line has no effect when error happens
                    return finishWithStatus(exchange, HttpStatus.UNAUTHORIZED);
                });
    }

有人能解释一下为什么我在这两种情况下都返回Mono。但是,如果A我嵌套了onErrorResume(在onErrorResume的“root”Mono我创建了另一个Mono,它有自己的onErrorResume)。

我觉得我错过了一些基本的东西,比如我需要“加入”两个Mono,或者说从最深处的onErrorResume冒出一些Mono. error到顶部?

处理嵌套错误的通用方法是什么(就像上面的情况,当遇到错误时,您必须发送另一个请求,而这反过来可能会以错误告终)。

我将非常感谢有关此事的任何建议或样本。


共1个答案

匿名用户

响应式编程的基本规则:在您订阅之前不会发生任何事情

finish与状态()有效,因为您通过返回Mono将发布者值传递给下一个过滤器

您正在logout()方法中创建响应运算符链,但从未订阅发布者或将发布者传递给下一个过滤器。因此,即使您调用此方法,也不会发生任何事情

另一点是您不能在filter()方法中返回logout()方法,因为filter()的返回类型是Mono

您应该更改logout()方法的返回类型:

protected Mono<Void> logout(ServerWebExchange exchange) {
    return webClient
            .post()
            .uri(...)
            .retrieve()
            .bodyToMono(Void.class)
            .doOnSuccess(any -> {
                log.info("Successfully logged out user");
            })
            .then(finishWithStatus(exchange, HttpStatus.UNAUTHORIZED))
            .onErrorResume(e -> {
                log.error("Failed to logout user", e);
                return finishWithStatus(exchange, HttpStatus.UNAUTHORIZED);
            });
}