spring cloud gateway - 日志
spring cloud gateway - 日志
实现日志
前提:spring cloud gateway是基于webflux的项目,所以不能像使用spring mvc一样直接获取request body。
参考博客:
- SpringCloud Gateway获取post请求体(request body)
- 获取SpringCloud gateway 响应的response的值,可以查看、修改
下面会讲述两种获取request body的方式(对应不同的版本)
第一种:重新构造再转发
如果我们在spring cloud gateway 封装之前读取了一次request body,比如打印request body日志,在下游获取数据的时候会出现错误:[spring cloud] [error] java.lang.IllegalStateException: Only one connection receive subscriber allowed. 因为request body只能读取一次,它是属于消费类型的。
实现思路为:
首先读取原请求的数据,然后构造一个新的请求,将原请求的数据封装到新的请求中,然后再转发出去。
这种方法在spring-boot-starter-parent 2.0.6.RELEASE + Spring Cloud Finchley.SR2 body 中生效
但是在spring-boot-starter-parent 2.1.0.RELEASE + Spring Cloud Greenwich.M3 body 中不生效,总是为空
重写的拦截方法filter
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {Route gatewayUrl = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);URI uri = gatewayUrl.getUri();ServerHttpRequest request = (ServerHttpRequest)exchange.getRequest();String URIPath = request.getURI().toString();String path = request.getPath().value();String method = request.getMethodValue();String instance = uri.getAuthority();HttpHeaders header = request.getHeaders();//缓存读取的request body信息AtomicReference<String> bodyRef = new AtomicReference<>();Flux<DataBuffer> fluxBody = exchange.getRequest().getBody();fluxBody.subscribe(buffer -> {CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());DataBufferUtils.release(buffer);bodyRef.set(charBuffer.toString());});String bodyStr = bodyRef.get();//获取request bodylog.info("请求体参数:{}",bodyStr); //封装新的requestDataBuffer bodyDataBuffer = stringBuffer(bodyStr);Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);request = new ServerHttpRequestDecorator(request){@Overridepublic Flux<DataBuffer> getBody() {return bodyFlux;}}; return chain.filter(exchange.mutate().request(request).build());
}
缓存body的方法
protected DataBuffer stringBuffer(String value) {byte[] bytes = value.getBytes(StandardCharsets.UTF_8);NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);buffer.write(bytes);return buffer;
}
第二种:获取缓存里面的body
这种方式就是解决在spring-boot-starter-parent 2.1.0.RELEASE + Spring Cloud Greenwich.M3 body 中不生效,总是为空的问题
实现思路:
在filter中通过cachedRequestBodyObject缓存字段获取request body信息,这种解决,一不会带来重复读取问题,二不会带来requestbody取不全问题。三在低版本的Spring Cloud Finchley.SR2也可以运行。
路由配置:
在配置中添加Predicate方法readBody(Object.class,requestBody -> true)
@Bean
public RouteLocator routeLocatorPermission(RouteLocatorBuilder builder) {return builder.routes().route(PERMISSION_ROUTE_ID,r -> r.path(PERMISSION_ROUTE_PATH).and().readBody(Object.class,requestBody -> true).filters(f -> f.stripPrefix(3).hystrix(config -> config.setName("hystrixName").setFallbackUri("forward:/fallback")).requestRateLimiter(config -> config.setKeyResolver(ipKeyResolver).setRateLimiter(myRedisRateLimiter)).filter(oauthFilter)).uri("lb://BOSS-BES-PERMISSION")).build();
}
配置日志拦截
可以通过Object requestBody = exchange.getAttribute("cachedRequestBodyObject")
直接获取body
@Component
public class GatewayRequestLogFilter implements GlobalFilter, Ordered {private static Logger logger = LoggerFactory.getLogger(GatewayRequestLogFilter.class);@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();logger.info("path: " + request.getPath());logger.info("address: " + request.getRemoteAddress());logger.info("method: " + request.getMethodValue());logger.info("URI: " + request.getURI());logger.info("Headers: " + request.getHeaders());Object requestBody = exchange.getAttribute("cachedRequestBodyObject");logger.info("body: "+ requestBody);return chain.filter(exchange);}@Overridepublic int getOrder() {return Ordered.HIGHEST_PRECEDENCE;}
}
注意事项:
如果是get请求,get请求使用readBody会报错
如果是post请求,Content-Type是application/x-www-form-urlencoded,readbody为 String.class
如果是post请求,Content-Type是application/json,readbody为 Object.class
最后附上响应拦截记录日志代码:
@Component
public class GatewayResponseLogFilter implements GlobalFilter, Ordered {private static Logger logger = LoggerFactory.getLogger(GatewayResponseLogFilter.class);@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpResponse originalResponse = exchange.getResponse();DataBufferFactory bufferFactory = originalResponse.bufferFactory();ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {@Override@SuppressWarnings("unchecked")public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {if (body instanceof Flux) {Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;return super.writeWith(fluxBody.map(dataBuffer -> {byte[] content = new byte[dataBuffer.readableByteCount()];dataBuffer.read(content);DataBufferUtils.release(dataBuffer);String result = new String(content, Charset.forName("UTF-8"));logger.info("response body: " + result);byte[] uppedContent = new String(content, Charset.forName("UTF-8")).getBytes();return bufferFactory.wrap(uppedContent);}));}return super.writeWith(body);}};return chain.filter(exchange.mutate().response(decoratedResponse).build());}@Overridepublic int getOrder() {return -2;}
}
spring cloud gateway - 日志相关推荐
- spring cloud gateway之filter篇
点击上方"方志朋",选择"置顶或者星标" 你的关注意义重大! 在上一篇文章详细的介绍了Gateway的Predict,Predict决定了请求由哪一个路由处理, ...
- Spring Cloud Gateway之Predict篇
Spring Cloud gateway工作流程 在之前的文章的Spring Cloud GateWay初体验中,大家已经对Spring Cloud Gateway的功能有一个初步的认识,网关作为一个 ...
- 实战 Spring Cloud Gateway 之限流篇
来源:https://www.aneasystone.com/archives/2020/08/spring-cloud-gateway-current-limiting.html 话说在 Sprin ...
- Spring Cloud Gateway 入门
认识 Spring Cloud Gateway Spring Cloud Gateway 是一款基于 Spring 5,Project Reactor 以及 Spring Boot 2 构建的 API ...
- java版电子商务spring cloud分布式微服务b2b2c社交电商-spring cloud gateway之filter篇
社交电商平台源码请加企鹅求求:一零三八七七四六二六.filter的作用和生命周期 由filter工作流程点,可以知道filter有着非常重要的作用,在"pre"类型的过滤器可以做参 ...
- 从0开始构建你的api网关--Spring Cloud Gateway网关实战及原理解析
API 网关 API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题 ...
- Spring Cloud Gateway(过滤器)
在上一篇文章中,我们了解了 Spring Cloud Gateway 作为网关所具备的基础功能:路由.本篇我们将关注它的另一个功能:过滤器. Spring Cloud Gateway 已经内置了很多实 ...
- Spring Cloud Gateway之负载均衡
本人最近在学习Spring Cloud Gateway但是发现网上的相关文章都没有介绍其如何使用负载均衡策略,那么本篇文章就给大家带来如何使用Spring Cloud Gateway负载均衡策略. ...
- 有什么办法动态更改yml的值吗_基于Redis实现Spring Cloud Gateway的动态管理
转载本文需注明出处:微信公众号EAWorld,违者必究. 引言: Spring Cloud Gateway是当前使用非常广泛的一种API网关.它本身能力并不能完全满足企业对网关的期望,人们希望它可以提 ...
最新文章
- ztree 自定义参数_zTree树插件使用方法及自定义控件实践_蓝戒的博客
- 北京超前布局通用人工智能 我国首个超大规模智能模型系统发布
- C++类型转换: static_cast const_cast reinterpret_cast dynamic_cast
- wxWidgets:SVG 示例
- linux apt-get dpkg,linux的sudo apt-get install 和dpkg -i package.deb命令
- php过去mysql数据表是空_PHP向mysql中写数据,在phpmyadmin中为空,直接打印有数据?...
- 被400万人痛骂!在中国火了22年的“洋网红”,套路彻底失灵了?
- Python_notes_05
- 络达1562系统深度睡眠后RTC唤醒应用
- 计算机语言的正交性,什么是“正交性”?
- 故障诊断分类 matlab代码 轴承内圈、外圈、滚动体故障分类
- 各纬度气候分布图_气候气压带图_世界气候气压带风带分布图要图(需要表识纬度)-4d影院专题信息栏目...
- 打开损坏的Word文档-word修复_目前只用过打开并修复
- 轻聊 - 聊天室的设计思路
- 关于H3C交换机配置MSTP
- 前端自动生成目录结构
- Nuist ACM集训队寒假训练计划
- com.alibaba.fastjson.JSON ,对象 转JSON字符串时,对字段名做了转换,需要注意啦
- 软件测试物理机环境基础
- geostudio2007破解版使用碰到的问题