从 ServerHttpRequest / Flux<DataBuffer> 获取请求正文字符串
Posted
技术标签:
【中文标题】从 ServerHttpRequest / Flux<DataBuffer> 获取请求正文字符串【英文标题】:Get request body string from ServerHttpRequest / Flux<DataBuffer> 【发布时间】:2019-12-25 00:51:00 【问题描述】:我使用的是 spring boot 版本 - 2.0.6.RELEASE 和 spring cloud 版本 - Finchley.SR2
我已经创建了自定义网关过滤器来修改请求正文。
但是在使用 Flux 将请求正文转换为字符串时,我得到一个空字符串。我需要一种方法来获取与我的请求正文对应的字符串。
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain)
ServerHttpRequest request = (ServerHttpRequest) exchange.getRequest();
String s = resolveBodyFromRequest(request);
/* s comes out to be "" */
return chain.filter(newExchange);
private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest)
//Get the request body
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();
【问题讨论】:
【参考方案1】:细化@tony.hokan answer https://***.com/a/64080867/1484823 使用spring cloud gateway rewrite body request 将请求正文(可能还有响应正文)保存为org.springframework.web.server.ServerWebExchange
的属性
@Bean
public RouteLocator myRouteSavingRequestBody(RouteLocatorBuilder builder)
return builder.routes()
.route("my-route-id",
p -> p
.path("/v2/**") //your own path filter
.filters(f -> f
.modifyResponseBody(String.class, String.class,
(webExchange, originalBody) ->
if (originalBody != null)
webExchange.getAttributes().put("cachedResponseBodyObject", originalBody);
return Mono.just(originalBody);
else
return Mono.empty();
)
.modifyRequestBody(String.class, String.class,
(webExchange, originalBody) ->
if (originalBody != null)
webExchange.getAttributes().put("cachedRequestBodyObject", originalBody);
return Mono.just(originalBody);
else
return Mono.empty();
)
)
.uri("https://myuri.org")
)
.build();
在您自己的过滤器中,获取 requestBody,如下所示:
@Override
public GatewayFilter apply(Object config)
return (exchange, chain) ->
String requestBody = exchange.getAttribute("cachedRequestBodyObject");
;
【讨论】:
您为我节省了大量时间和研究。非常感谢。你是英雄。【参考方案2】:这是 spring cloud gateway 2.2.5 中的另一种方法,我们将使用 ReadBodyPredicateFactory,因为这将使用属性键 cachedRequestBodyObject 将 requestBody 缓存到 ServerWebExchange
创建始终为真的谓词
@Component
public class TestRequestBody implements Predicate
@Override
public boolean test(Object o)
return true;
在application.yml中,添加谓词
spring:
cloud:
gateway:
routes:
....
predicates:
.....
- name: ReadBodyPredicateFactory
args:
inClass: "#T(String)"
predicate: "#@testRequestBody"
在您自己的过滤器中,获取 requestBody,如下所示:
@Override
public GatewayFilter apply(Object config)
return (exchange, chain) ->
String requestBody = exchange.getAttribute("cachedRequestBodyObject");
;
【讨论】:
【参考方案3】:您可以使用 ModifyRequestBodyGatewayFilterFactory,我相信它包含在 Spring Cloud Gateway 2.0.2 中,它是 Finchley 的一部分。
例如:
@Override
public GatewayFilter apply(Config config)
return (exchange, chain) ->
ModifyRequestBodyGatewayFilterFactory.Config modifyRequestConfig = new ModifyRequestBodyGatewayFilterFactory.Config()
.setContentType(ContentType.APPLICATION_JSON.getMimeType())
.setRewriteFunction(String.class, String.class, (exchange1, originalRequestBody) ->
String modifiedRequestBody = yourMethodToModifyRequestBody(originalRequestBody);
return Mono.just(modifiedRequestBody);
);
return new ModifyRequestBodyGatewayFilterFactory().apply(modifyRequestConfig).filter(exchange, chain);
;
【讨论】:
【参考方案4】:一旦您阅读(通过阅读记录)请求正文,请求就会自行删除。 spring cloud gateway需要记录请求体的内容,但是请求体只能读取一次。如果请求body读取后没有封装,后面的服务将无法读取body数据。 follow this
【讨论】:
以上是关于从 ServerHttpRequest / Flux<DataBuffer> 获取请求正文字符串的主要内容,如果未能解决你的问题,请参考以下文章
Spring Webflux注解的rest控制器不支持ServerHttpRequest作为方法参数:java.lang.NoSuchMethodException
sudo: unable to resolve host iZ2zecsdy8flu603bmdg1bZ