我有一个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
到顶部?
处理嵌套错误的通用方法是什么(就像上面的情况,当遇到错误时,您必须发送另一个请求,而这反过来可能会以错误告终)。
我将非常感谢有关此事的任何建议或样本。
响应式编程的基本规则:在您订阅之前不会发生任何事情
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);
});
}