Spring Gateway 同时拦截输入输出做日志操作
Spring Gateway 同时拦截输入输出做日志操作,包括request body, 和response body
主要靠代理模式,参考
https://stackoverflow.com/questions/47182961/copy-of-the-request-response-body-on-a-spring-reactive-app
需要创建 request , response, ServerWebExchangeDecorator, GlobalFilter
public class PartnerServerHttpRequestDecorator extends ServerHttpRequestDecorator { public PartnerServerHttpRequestDecorator(ServerHttpRequest delegate) { super(delegate); } private final StringBuilder cachedBody = new StringBuilder(); @Override public Flux<DataBuffer> getBody() { return super.getBody().doOnNext(this::cache); } private void cache(DataBuffer buffer) { cachedBody.append(UTF_8.decode(buffer.asByteBuffer())); } public String getCachedBody() { return cachedBody.toString(); } }
public class PartnerServerHttpResponseDecorator extends ServerHttpResponseDecorator { private final StringBuilder cachedBody = new StringBuilder(); public PartnerServerHttpResponseDecorator(ServerHttpResponse delegate) { super(delegate); } @Override public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { if (body instanceof Flux) { Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body; return super.writeWith(fluxBody.buffer().map(dataBuffers -> { // 1.获取response中的内容 DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); DataBuffer join = dataBufferFactory.join(dataBuffers); byte[] content = new byte[join.readableByteCount()]; join.read(content); DataBufferUtils.release(join); String bodyStr = new String(content, StandardCharsets.UTF_8); cachedBody.append(bodyStr); return bufferFactory().wrap(bodyStr.getBytes()); })); } return super.writeWith(body); } public String getCachedBody() { return cachedBody.toString(); } }
public class PartnerServerWebExchangeDecorator extends ServerWebExchangeDecorator { private final ServerHttpRequestDecorator requestDecorator; private final ServerHttpResponseDecorator responseDecorator; public PartnerServerWebExchangeDecorator(ServerWebExchange delegate) { super(delegate); this.requestDecorator = new PartnerServerHttpRequestDecorator(delegate.getRequest()); this.responseDecorator = new PartnerServerHttpResponseDecorator(delegate.getResponse()); } @Override public ServerHttpRequest getRequest() { return requestDecorator; } @Override public ServerHttpResponse getResponse() { return responseDecorator; } }
然后实现GlobalFilter 即可
@Slf4j @Component public class OperatorLogPostFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("entry OperatorLogPostFilter"); // 使用之前声明的 PartnerServerWebExchangeDecorator partnerServerWebExchangeDecorator = new PartnerServerWebExchangeDecorator(exchange); return chain.filter(partnerServerWebExchangeDecorator).then(Mono.fromRunnable(()-> { // 实际返回的就是自己装饰/代理 好的类型 PartnerServerHttpRequestDecorator request = (PartnerServerHttpRequestDecorator) partnerServerWebExchangeDecorator.getRequest(); PartnerServerHttpResponseDecorator response = (PartnerServerHttpResponseDecorator) partnerServerWebExchangeDecorator.getResponse(); // 记录的操作在这里进行 log.info("request api:{},request header:{}, request body:{}, response body:{}", request.getPath().value(), request.getHeaders().getFirst(CommonHeader.ACCOUNT_NAME), request.getCachedBody(), response.getCachedBody()); })); } @Override public int getOrder() { // 这个地方非常坑,一定要小于-1才会进入到response 的代理中,因为 NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER 的值是-1, 如果大于它, NettyWriteResponseFilter 会直接返回,就不会执行自己定义的response.大坑,在这里用@Order好像不好使, 得实现Ordered 接口 // return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1; return -5; } }
记折腾了3天的问题
posted on 2023-11-10 17:36 cococooder 阅读(120) 评论(0) 编辑 收藏 举报