我有一个Webflux应用程序,其中有一个ServerWebExchangeDecorator来装饰请求和响应。我有一些重写来做一些日志记录,然后调用超级方法。这就是我的代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebExchangeDecorator;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Component
public class LoggingWebFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return chain.filter(decorate(exchange));
}
private ServerWebExchange decorate(ServerWebExchange exchange) {
final ServerHttpRequest decoratedRequest = new LoggingServerHttpRequestDecorator(exchange.getRequest());
final ServerHttpResponse decoratedResponse = new LoggingServerHttpResponseDecorator(exchange.getResponse());
return new ServerWebExchangeDecorator(exchange) {
@Override
public ServerHttpRequest getRequest() {
return decoratedRequest;
}
@Override
public ServerHttpResponse getResponse() {
return decoratedResponse;
}
};
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import reactor.core.publisher.Flux;
public class LoggingServerHttpRequestDecorator extends ServerHttpRequestDecorator {
private static final Logger logger = LoggerFactory.getLogger(LoggingServerHttpRequestDecorator.class);
public LoggingServerHttpRequestDecorator(ServerHttpRequest delegate) {
super(delegate);
}
@Override
public Flux<DataBuffer> getBody() {
logger.info("getBody method");
return super.getBody();
}
}
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import reactor.core.publisher.Mono;
public class LoggingServerHttpResponseDecorator extends ServerHttpResponseDecorator {
private static final Logger logger = LoggerFactory.getLogger(LoggingServerHttpResponseDecorator.class);
public LoggingServerHttpResponseDecorator(ServerHttpResponse delegate) {
super(delegate);
}
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
logger.info("writeWith method");//THIS LINE IS NOT EXECUTED WHEN AN EXCEPTION IS THROWN
return super.writeWith(body);
}
@Override
public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
logger.info("writeAndFlushWith method");
return super.writeAndFlushWith(body);
}
}
当我用POST请求创建一个happy path时,这很好,但是当抛出一个异常时,Response Decorator被省略了,我的自定义代码也没有被执行。
这是用于复制问题的控制器代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/decorator-demo")
public class DecoratorDemoController {
/** The Constant logger. */
private static final Logger logger = LoggerFactory.getLogger(DecoratorDemoController.class);
@PostMapping(produces = MediaType.APPLICATION_STREAM_JSON_VALUE, consumes = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Mono<ResponseEntity<String>> postData(@RequestBody String id) {
logger.info("attempting to post the data");
if(id.length() == 1){
Mono<String> created = Mono.just(id);
return created.flatMap(vo -> Mono.just(ResponseEntity.status(HttpStatus.CREATED).body(vo)));
}
throw new IllegalArgumentException("String length must be 1");
}
}
型
当我发布一个字符时,我有我期望的日志:
LoggingServerHttpRequestDecorator : getBody method
DecoratorDemoController : attempting to post the data
LoggingServerHttpResponseDecorator : writeWith method
型
但是当我发布多个字符时,这是我的日志:
LoggingServerHttpRequestDecorator : getBody method
DecoratorDemoController : attempting to post the data
AbstractErrorWebExceptionHandler : [0b933716] 500 Server Error for HTTP POST "/decorator-demo"
型
我是做错了什么,还是错过了什么?
2条答案
按热度按时间2exbekwf1#
试试这个
字符串
htrmnn0y2#
对于那些正在与请求或响应装饰器不执行if的问题作斗争的人;
Filter
都会抛出错误。router
>handler
)都会抛出一个错误,这个错误在任何.errorXXX()
Map方法中都没有处理。让我们看看下面的例子:
字符串
注意事项:
1.如果链接中的任何Filter或任何其他类向为请求启动的Mono链发出错误信号,则不会执行装饰器(
ServerHttpRequestDecorator
或ServerHttpResponseDecorator
)。1.如果任何Filter或类抛出错误,它将到达此Filter的errorHandler,一旦此Filter(日志记录)将错误提交到链,则它将被
ErrorWebExceptionHandler
捕获1.此方法 * 仅适用于Happy Path*
1.请求装饰器的
public Flux<DataBuffer> getBody()
方法只有在传入的请求有body时才会被调用!这意味着,对于GET
请求或任何其他没有body的请求,甚至不会调用RequestDecorator。所以你需要依赖CONTENT_LENGTH
头文件并手动调用日志记录!(yikes)1.您需要处理 * GlobalErrorHandler中的Request & Response日志记录,以防出现故障场景 。
1.在链中缓冲请求和响应的整个方法 * 必须高度考虑到,通过缓冲其内容,Reactive的主要目的是失败的!
使用的堆栈:
spring-boot-starter-webflux:3.x.x
个@Controller
和@RestControllerAdvice
相反请纠正我,如果其他人已经找到了一个推荐/优化的解决方案。