美文网首页
SpringCloud Gateway获取post请求体(req

SpringCloud Gateway获取post请求体(req

作者: 简单_36e0 | 来源:发表于2018-12-12 01:43 被阅读0次

    获取spring cloud gateway POST请求体的时候,会有很多坑,网上大多数解决方案是

    /**

    这种方法在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 中不生效,总是为空

    /**

    这种方法在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 中不生效,总是为空

    */privateStringresolveBodyFromRequest(ServerHttpRequest serverHttpRequest){

            Flux<DataBuffer> body = serverHttpRequest.getBody();

            AtomicReference<String> bodyRef = new AtomicReference<>();

            body.subscribe(buffer -> {

                CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());

                DataBufferUtils.release(buffer);

                bodyRef.set(charBuffer.toString());

            });

            return bodyRef.get();

        }

    但是实际这种解决方案(例如 这篇文章)会带来很多问题,比如request不能在其他filter中获取,会报错:

    reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalStateException: Only one connection receive subscriber allowed.Caused by: java.lang.IllegalStateException: Only one connection receive subscriber allowed.

    针对这种不能重复获取的问题,网上通用解决是把request重新包装,继续传递,比如 这篇文章的解决方案。

    但是这种方案还会带来request body获取不完整,只能获取1024B的数据,这个问题暂时没有很好的解法,很头痛,在给官方提issues的时候,issues709 和issues707 的时候,对方让我参看一个类ModifyRequestBodyGatewayFilterFactory.java,说真的并没有看懂,最后翻源码的时候,发现了一个预言类,ReadBodyPredicateFactory ,发现里面缓存了request body的信息,于是在自定义router中配置了ReadBodyPredicateFactory,然后在filter中通过cachedRequestBodyObject缓存字段获取request body信息,这种解决,一不会带来重复读取问题,二不会带来requestbody取不全问题。三在低版本的Spring Cloud Finchley.SR2也可以运行。

    step1:

    step 1:现在自动以router里面配置ReadBodyPredicate预言类:

    RouteLocatorBuilder.Builder serviceProvider = builder.

                    routes().route("gateway-sample",

                        r -> r.readBody(Object.class, requestBody -> {

                            log.info("requestBody is {}", requestBody);

                            // 这里不对body做判断处理

                            return true;

                    }).and().path("/service").

                            filters(f -> {

                                f.filter(requestFilter);

                                return f;

                            })

                            .uri("http://127.0.0.1:8009"));

            RouteLocator routeLocator = serviceProvider.build();

    step2:在自定义filter中获取缓存了的request body:

    ObjectrequestBody = exchange.getAttribute("cachedRequestBodyObject");

    至此问题解决,完整代码在我的github上面。参考这里

    参考:

    http://blog.51cto.com/thinklili/2329184

    https://www.cnblogs.com/cafebabe-yun/p/9328554.html

    https://blog.csdn.net/tianyaleixiaowu/article/details/83375246

    相关文章

      网友评论

          本文标题:SpringCloud Gateway获取post请求体(req

          本文链接:https://www.haomeiwen.com/subject/ticczftx.html