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 - 日志相关推荐

  1. spring cloud gateway之filter篇

    点击上方"方志朋",选择"置顶或者星标" 你的关注意义重大! 在上一篇文章详细的介绍了Gateway的Predict,Predict决定了请求由哪一个路由处理, ...

  2. Spring Cloud Gateway之Predict篇

    Spring Cloud gateway工作流程 在之前的文章的Spring Cloud GateWay初体验中,大家已经对Spring Cloud Gateway的功能有一个初步的认识,网关作为一个 ...

  3. 实战 Spring Cloud Gateway 之限流篇

    来源:https://www.aneasystone.com/archives/2020/08/spring-cloud-gateway-current-limiting.html 话说在 Sprin ...

  4. Spring Cloud Gateway 入门

    认识 Spring Cloud Gateway Spring Cloud Gateway 是一款基于 Spring 5,Project Reactor 以及 Spring Boot 2 构建的 API ...

  5. java版电子商务spring cloud分布式微服务b2b2c社交电商-spring cloud gateway之filter篇

    社交电商平台源码请加企鹅求求:一零三八七七四六二六.filter的作用和生命周期 由filter工作流程点,可以知道filter有着非常重要的作用,在"pre"类型的过滤器可以做参 ...

  6. 从0开始构建你的api网关--Spring Cloud Gateway网关实战及原理解析

    API 网关 API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题 ...

  7. Spring Cloud Gateway(过滤器)

    在上一篇文章中,我们了解了 Spring Cloud Gateway 作为网关所具备的基础功能:路由.本篇我们将关注它的另一个功能:过滤器. Spring Cloud Gateway 已经内置了很多实 ...

  8. Spring Cloud Gateway之负载均衡

    ​ 本人最近在学习Spring Cloud Gateway但是发现网上的相关文章都没有介绍其如何使用负载均衡策略,那么本篇文章就给大家带来如何使用Spring Cloud Gateway负载均衡策略. ...

  9. 有什么办法动态更改yml的值吗_基于Redis实现Spring Cloud Gateway的动态管理

    转载本文需注明出处:微信公众号EAWorld,违者必究. 引言: Spring Cloud Gateway是当前使用非常广泛的一种API网关.它本身能力并不能完全满足企业对网关的期望,人们希望它可以提 ...

最新文章

  1. ztree 自定义参数_zTree树插件使用方法及自定义控件实践_蓝戒的博客
  2. 北京超前布局通用人工智能 我国首个超大规模智能模型系统发布
  3. C++类型转换: static_cast const_cast reinterpret_cast dynamic_cast
  4. wxWidgets:SVG 示例
  5. linux apt-get dpkg,linux的sudo apt-get install 和dpkg -i package.deb命令
  6. php过去mysql数据表是空_PHP向mysql中写数据,在phpmyadmin中为空,直接打印有数据?...
  7. 被400万人痛骂!在中国火了22年的“洋网红”,套路彻底失灵了?
  8. Python_notes_05
  9. 络达1562系统深度睡眠后RTC唤醒应用
  10. 计算机语言的正交性,什么是“正交性”?
  11. 故障诊断分类 matlab代码 轴承内圈、外圈、滚动体故障分类
  12. 各纬度气候分布图_气候气压带图_世界气候气压带风带分布图要图(需要表识纬度)-4d影院专题信息栏目...
  13. 打开损坏的Word文档-word修复_目前只用过打开并修复
  14. 轻聊 - 聊天室的设计思路
  15. 关于H3C交换机配置MSTP
  16. 前端自动生成目录结构
  17. Nuist ACM集训队寒假训练计划
  18. com.alibaba.fastjson.JSON ,对象 转JSON字符串时,对字段名做了转换,需要注意啦
  19. 软件测试物理机环境基础
  20. geostudio2007破解版使用碰到的问题

热门文章

  1. 微信公号 DIY:一小时搭建微信聊天机器人
  2. 【软件工程大作业】快递代拿小程序项目 (第十组)
  3. 工地发生工伤事故鉴定是由谁负责
  4. 在互联网大厂实习之后,我明白了这些事
  5. win10默认安装路径修改_解放C盘!2种方法教你修改默认安装目录!
  6. 3D设计必备!5个免高质量的 HDRI 环境贴图网站
  7. 关于DOSBOX启动时自动挂载到指定盘及目录问题
  8. 一起学做扣扣(python) — 预告
  9. Java码农坎坷之路~单例抽象类接口
  10. 01 VVC中编码块的划分结构