前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCloudGateway笔记(6)-请求体不全

SpringCloudGateway笔记(6)-请求体不全

作者头像
yingzi_code
发布2019-08-30 22:08:10
2K0
发布2019-08-30 22:08:10
举报

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/yingziisme/article/details/94591049

实际使用遇到的问题 – 在filter里面获取RequestBody不完整以及LEAK MEMORY的问题

第一种获取方式

在网上找到的最常见的一种获取RequestBody的方式是

代码语言:javascript
复制
    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest){
        //获取请求体
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        StringBuilder sb = new StringBuilder();

        body.subscribe(buffer -> {
            byte[] bytes = new byte[buffer.readableByteCount()];
            buffer.read(bytes);
            DataBufferUtils.release(buffer);
            String bodyString = new String(bytes, StandardCharsets.UTF_8);
            sb.append(bodyString);
        });
        return sb.toString();
    }

这种方式会导致获取到的body不完整

在新版本SpringBoot 2.1.5.RELEAS +SpringCloud Greenwich.SR1中

获取不到RequestBody

完整的测试代码如下

代码语言:javascript
复制
@Slf4j
@Component
public class RequestBodyFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (HttpMethod.POST.equals(exchange.getRequest().getMethod()) && null != exchange.getRequest().getHeaders().getContentType()
                && exchange.getRequest().getHeaders().getContentType().includes(MediaType.APPLICATION_JSON)
                && !exchange.getRequest().getHeaders().getContentType().includes(MediaType.MULTIPART_FORM_DATA)) {

            String requestbody = resolveBodyFromRequest(exchange.getRequest());
            log.info("requestbody: \n {}", requestbody);
            return chain.filter(exchange.mutate().request(generateNewRequest(exchange.getRequest(), requestbody)).build());
        }
        return chain.filter(exchange);
    }

    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
        //获取请求体
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        StringBuilder sb = new StringBuilder();

        body.subscribe(buffer -> {
            byte[] bytes = new byte[buffer.readableByteCount()];
            buffer.read(bytes);
            String bodyString = new String(bytes, StandardCharsets.UTF_8);
            sb.append(bodyString);
            log.info("======\n{}", bodyString);
            DataBufferUtils.release(buffer);
        });
        return sb.toString();
    }

    private ServerHttpRequest generateNewRequest(ServerHttpRequest request, String requestBody) {
        URI ex = UriComponentsBuilder.fromUri(request.getURI()).build(true).toUri();
        ServerHttpRequest newRequest = request.mutate().uri(ex).build();
        DataBuffer dataBuffer = stringBuffer(requestBody);
        Flux<DataBuffer> flux = Flux.just(dataBuffer);
        newRequest = new ServerHttpRequestDecorator(newRequest) {
            @Override
            public Flux<DataBuffer> getBody() {
                return flux;
            }
        };
        return newRequest;
    }

    private 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;
    }

    @Override
    public int getOrder() {
        return -5;
    }
}

发起请求输出打印

代码语言:javascript
复制
2019-05-24 22:12:51.644  INFO 10688 --- [ctor-http-nio-3] c.m.d.gateway.filter.RequestBodyFilter   : requestbody: 
 
2019-05-24 22:12:51.654  INFO 10688 --- [ctor-http-nio-3] com.mt.demo.gateway.filter.MyFilter2     : this is a pre filter2
2019-05-24 22:12:52.211  INFO 10688 --- [ctor-http-nio-3] com.mt.demo.gateway.filter.MyFilter      : this is a pre filter
2019-05-24 22:12:52.228  INFO 10688 --- [ctor-http-nio-3] c.m.d.gateway.filter.RequestBodyFilter   : ======
{
	"a": "abeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"b": "bbeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"c": "cbeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"d": "dbeqwertyuiopa
2019-05-24 17:12:52.230  INFO 10688 --- [ctor-http-nio-3] c.m.d.gateway.filter.RequestBodyFilter   : ======
sdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"e": "ebeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"ae": "abeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"be": "bbeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"ce": "cbeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"de": "dbeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"ee": "ebeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"aee": "abeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"bee": "bbeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"cee": "cbeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"dee": "dbeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"eee": "ebeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"aeee": "abeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"beee": "beqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"ceee": "ceqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"deee": "eqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopd",
	"eeee": "eqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiope",
	"asdfeee": "aeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"beedsfe": "beqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"ceesde": "ceqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"deesdfe": "deqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"eeesde": "eeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuioeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbn",
	"aaaaaaa": "aeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"bccccccccc": "eqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopb",
	"cdddddd": "ceqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"dddddddd": "deqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop",
	"edddddddd": "eqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiopeqwertyuiopasdfghjklzxcvbnm,asdfghjklqwertyuiop"
}
2019-05-24 22:12:52.245  INFO 10688 --- [ioEventLoop-4-1] com.mt.demo.gateway.filter.MyFilter      : websession: 46fad4ce-4137-49c2-b694-93f5f140e2d9

可以看到subscribe的消息体延时收到

第二种获取方式

这种方式在测试的时候没有问题,但是进入生产环境会报

LEAK: ByteBuf. release () was not called before it’s garbage-collected

但是没找到这种方法怎么去释放buffer

代码语言:javascript
复制
@Slf4j
@Component
public class RequestBodyFilter1 implements GlobalFilter, Ordered {

    private static final List<HttpMessageReader<?>> MESSAGE_READERS = HandlerStrategies.withDefaults().messageReaders();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (HttpMethod.POST.equals(exchange.getRequest().getMethod()) && null != exchange.getRequest().getHeaders().getContentType()
                && exchange.getRequest().getHeaders().getContentType().includes(MediaType.APPLICATION_JSON)
                && !exchange.getRequest().getHeaders().getContentType().includes(MediaType.MULTIPART_FORM_DATA)) {

            return readBody(exchange, chain);
        }
        return chain.filter(exchange);
    }

    private Mono<Void> readBody(ServerWebExchange exchange, GatewayFilterChain chain) {
        return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {
            DataBufferUtils.retain(dataBuffer);
            Flux<DataBuffer> cachedFlux = Flux.defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));

            ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
                @Override
                public Flux<DataBuffer> getBody() {
                    return cachedFlux;
                }
            };
            ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();

            return ServerRequest.create(mutatedExchange, MESSAGE_READERS).bodyToMono(String.class)
                    .doOnNext(objectValue -> {
                        log.info("----request body: \n{}\n", objectValue);
                    })
                    .then(chain.filter(mutatedExchange));
        });
    }

    @Override
    public int getOrder() {
        return -5;
    }
}
第三种获取方式

目前测试这种方式没有内存泄漏的问题,也能够获取到完整的RequestBody

代码语言:javascript
复制
@Slf4j
@Component
public class RequestBodyFilter2 implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (HttpMethod.POST.equals(exchange.getRequest().getMethod()) && null != exchange.getRequest().getHeaders().getContentType()
                && exchange.getRequest().getHeaders().getContentType().includes(MediaType.APPLICATION_JSON)
                && !exchange.getRequest().getHeaders().getContentType().includes(MediaType.MULTIPART_FORM_DATA)) {

            return DataBufferUtils.join(exchange.getRequest().getBody()).map(dataBuffer -> {
                byte[] bytes = new byte[dataBuffer.readableByteCount()];
                dataBuffer.read(bytes);
                DataBufferUtils.release(dataBuffer);
                return bytes;
            }).flatMap(bodyBytes -> {
                String msg = new String(bodyBytes, StandardCharsets.UTF_8);
                log.info("requestBody: \n {}", msg);
                exchange.getAttributes().put(Constants.CACHE_REQUEST_BODY, msg);
                return chain.filter(exchange.mutate().request(generateNewRequest(exchange.getRequest(), bodyBytes)).build());
            });
        }
        return chain.filter(exchange);
    }

    private ServerHttpRequest generateNewRequest(ServerHttpRequest request, byte[] bytes) {
        URI ex = UriComponentsBuilder.fromUri(request.getURI()).build(true).toUri();
        ServerHttpRequest newRequest = request.mutate().uri(ex).build();
        DataBuffer dataBuffer = stringBuffer(bytes);
        Flux<DataBuffer> flux = Flux.just(dataBuffer);
        newRequest = new ServerHttpRequestDecorator(newRequest) {
            @Override
            public Flux<DataBuffer> getBody() {
                return flux;
            }
        };
        return newRequest;
    }

    private DataBuffer stringBuffer(byte[] bytes) {
        NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
        return nettyDataBufferFactory.wrap(bytes);
    }


    @Override
    public int getOrder() {
        return -5;
    }
}

从第三种方式中可以看到

代码语言:javascript
复制
exchange.getAttributes().put(Constants.CACHE_REQUEST_BODY, msg);

将RequestBody存入exchange,就可以在后续流程通过exchange来获取

GITHUB代码地址

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年07月05日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一种获取方式
  • 第二种获取方式
  • 第三种获取方式
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com