Spring Cloud Gateway 获取响应体消息

一、场景介绍

  在通常情况下,微服务的业务功能都需要通过网关来进行转发,记录业务响应日志通过网关来记录是最有利的方式。

二、演示代码
  • 测试版本

    组件名版本号
    Spring Boot2.2.5.RELEASE
    Spring CloudHoxton.SR3
    Spring Cloud Alibaba2.2.1.RELEASE
  • 测试代码

    import com.google.common.base.Joiner;
    import com.google.common.collect.Lists;
    import lombok.extern.slf4j.Slf4j;
    import org.reactivestreams.Publisher;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
    import org.springframework.core.Ordered;
    import org.springframework.core.io.buffer.DataBuffer;
    import org.springframework.core.io.buffer.DataBufferFactory;
    import org.springframework.core.io.buffer.DataBufferUtils;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.MediaType;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    
    import java.nio.charset.Charset;
    import java.util.List;
    
    import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR;
    
    /**
     * @ClassName:   CustomResponseGlobalLogFilter
     * @Description: 自定义全局请求响应日志记录
     * @Author:      Rambo
     * @CreateDate:  2020/8/6 17:05
     * @UpdateUser:  Rambo
     * @UpdateDate:  2020/8/6 17:05
     * @Version:     1.0.0
     */
    @Component
    @Slf4j
    public class CustomResponseGlobalLogFilter implements GlobalFilter, Ordered {
    
        private static Joiner joiner = Joiner.on("");
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            // 获取响应对象
            ServerHttpResponse response = exchange.getResponse();
            DataBufferFactory bufferFactory = response.bufferFactory();
            ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(response) {
                @Override
                public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                    if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
                        // 获取响应 ContentType
                        String responseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
                        // 记录 JSON 格式数据的响应体
                        if (!StringUtils.isEmpty(responseContentType) && responseContentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
                            Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                            // 解决返回体分段传输
                            return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                                List<String> list = Lists.newArrayList();
                                dataBuffers.forEach(dataBuffer -> {
                                    byte[] content = new byte[dataBuffer.readableByteCount()];
                                    dataBuffer.read(content);
                                    DataBufferUtils.release(dataBuffer);
                                    list.add(new String(content, Charset.forName("UTF-8")));
                                });
                                String responseData = joiner.join(list);
                                log.info("<------------------------ RESPONSE RESULT = [{}]", responseData.replaceAll("\n","").replaceAll("\t",""));
                                return bufferFactory.wrap(responseData.getBytes());
                            }));
                        }
                    }
                    return super.writeWith(body);
                }
            };
            return chain.filter(exchange.mutate().response(responseDecorator).build());
        }
    
        @Override
        public int getOrder() {
            // 必须要小于 -1
            return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER-1;
        }
    }
    
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值