SpringCloud Gateway获取post请求体(request body)

获取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 中不生效,总是为空
*/
private String resolveBodyFromRequest(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的时候,issues709issues707 的时候,对方让我参看一个类ModifyRequestBodyGatewayFilterFactory.java,说真的并没有看懂,最后翻源码的时候,发现了一个预言类,ReadBodyPredicateFactory ,发现里面缓存了request body的信息,于是在自定义router中配置了ReadBodyPredicateFactory,然后在filter中通过cachedRequestBodyObject缓存字段获取request body信息,这种解决,一不会带来重复读取问题,二不会带来requestbody取不全问题。三在低版本的Spring Cloud Finchley.SR2也可以运行。

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:
      Object requestBody = exchange.getAttribute("cachedRequestBodyObject");

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

参考:
https://www.cnblogs.com/cafebabe-yun/p/9328554.html
https://blog.csdn.net/tianyaleixiaowu/article/details/83375246

转载于:https://blog.51cto.com/thinklili/2329184

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值