New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How do I get the request body in the global filter method? #1205
Comments
Thanks @ryanjbaxter, but with Spring Cloud 2.1.2, |
Fair point, but it doesnt mean you can't copy that class if you need it (I realize that is not ideal). @spencergibb maybe we should make that class |
we could I guess. |
I used the old version of return DataBufferUtils.join(exchange.getRequest().getBody())
.flatMap(dataBuffer -> {
DataBufferUtils.retain(dataBuffer);
Flux<DataBuffer> cachedFlux = Flux.defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return cachedFlux;
}
};
ServerWebExchange build = exchange.mutate().request(mutatedRequest).build();
return Mono.just(build)
.map(ex -> {
ServerRequest.create(ex, MESSAGE_READERS)
.bodyToMono(String.class)
.subscribe(
bodyString -> {
ex.getAttributes().put("requestBody",bodyString);
}
);
return ex;
})
.doOnNext(objectValue -> {
exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, objectValue);
exchange.getAttributes().put(CACHED_REQUEST_BODY_KEY, cachedFlux);
});
}).defaultIfEmpty(exchange).flatMap(webExchange -> Mono.just(exchange)); But if you post a request withi empty body,it will cause "Only one connection receive subscriber allowed".So I copied the Mono<DataBuffer> dataBufferMono = Flux.from(exchange.getRequest().getBody()).collectList().filter((list) -> {
if(list.isEmpty()){
list.add(new NettyDataBufferFactory(ByteBufAllocator.DEFAULT).allocateBuffer(0));
}
return true;
}).map((list) -> {
return ((DataBuffer)list.get(0)).factory().join(list);
}).doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
dataBufferMono.flatMap(dataBuffer->(...)) |
Did not find any good method so far. (remember, you could not modify and reset the body. Or I am fool, so did not find the way) the only method to modify the body content is use Java DSL r.path("/aaa").filters( f -> f.modifyRequestBody( xxxxxx )).uri("lb://aaa") for each route, I did not find any method for all routes ( or default-filters) so far. |
I use this code to parse the body private static final String CACHED_REQUEST_BODY_OBJ = "cached_request_body_obj";
private static List<HttpMessageReader<?>> messageReaders =
HandlerStrategies.withDefaults().messageReaders();
/**
* This method is inspired by {@link ReadBodyPredicateFactory}
*
* @param exchange the current exchange
* @param inClass the class to parse the body to
* @param <T> the type the body is parsed to
* @return Mono of type T of the parsed body
*/
static public <T> Mono<T> readBody(ServerWebExchange exchange, Class<T> inClass) {
T bodyObject = exchange.getAttribute(CACHED_REQUEST_BODY_OBJ);
return bodyObject != null
? Mono.just(bodyObject)
: getBody(exchange, inClass);
}
private static <T> Mono<T> getBody(ServerWebExchange exchange, Class<T> inClass) {
return ServerWebExchangeUtils.cacheRequestBodyAndRequest(
exchange,
request -> ServerRequest.create(exchange.mutate()
.request(request)
.build(), messageReaders)
.bodyToMono(inClass)
).doOnNext(bodyObject -> exchange.getAttributes()
.put(CACHED_REQUEST_BODY_OBJ, bodyObject)
); Sadly it does not work as a standalone. It only works when I use the .readBody(inClass, o -> true)
.filters(f -> f
.filter((exchange, chain) -> {
return readBody(exchange, inClass)
// Do logic with body
.then(chain.filter(exchange));
}))
.uri("http://exmaple.com")) without it I get
The ability to use the request body for custom logic in not a nice-to-have feature but rather a necessity. |
Closing due to age of the question. If you would like us to look at this issue, please comment and we will look at re-opening the issue. |
How do I get the request body in the global filter method?
Spring boot 2.1.6
Spring Cloud 2.1.2
Based on this comment (#747 (comment)), I tried to replicate the code, but with spring cloud 2.1.2 some of the classes are removed (CachedBodyOutputMessage)
The text was updated successfully, but these errors were encountered: