获取 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 的时候, issues709 和 issues707 的时候, 对方让我参看一个类, 说真的并没有看懂, 最后翻源码的时候, 发现了一个预言类, 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 上面. 参考这里.
参考:
SpringCloud Gateway 获取 post 请求体(request body)
来源: http://www.bubuko.com/infodetail-2881402.html