[英]Get request body string from ServerHttpRequest / Flux<DataBuffer>
我正在使用 spring 引导版本 - 2.0.6.RELEASE 和 spring 云版本 - 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();
}
您可以使用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);
};
}
这是 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 中,添加 Predicate
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");
};
}
一旦您阅读(通过阅读记录)请求正文,请求就会自行删除。 spring cloud gateway需要记录请求体的内容,但是请求体只能读取一次。 如果请求正文读取后没有封装,后面的服务将无法读取正文数据。 按照这个
@tony.hokan 回答https://stackoverflow.com/a/64080867/1484823使用 spring cloud gateway 重写正文请求的细化以将请求正文(和可能的响应正文)保存为org.springframework.web.server.ServerWebExchange
的属性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");
};
}
在路由配置中,在您的自定义配置之前添加 Spring CacheRequestBody
:
spring:
cloud:
gateway:
routes:
- id: cache_request_body_route
uri: lb://downstream
predicates:
- Path=/downstream/**
filters:
- name: CacheRequestBody
args:
bodyClass: java.util.LinkedHashMap
或者如果你正在使用。 属性代替。 yaml :
spring.cloud.gateway.routes[77].filters[2]=CacheRequestBody=java.util.LinkedHashMap
spring.cloud.gateway.routes[77].filters[3]=YourCustomFilter
现在,在 Spring CacheRequestBody
之后链中的每个过滤器中,您只需调用exchange.getAttribute(ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR);
即可获得请求正文的缓存副本。 :
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
LinkedHashMap<String,Object> body = exchange.getAttribute(ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR);
//do-stuff-with-body
return chain.filter(exchange);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.