Hello guys,
Is possible to add a filter to do caching based in a request and parameters?
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("testcache",
route -> route
.path("/testcache")
.filters(conf -> conf.filter(new CacheFilter()))
.uri("http://myurl.com")).build();
}
public class CacheFilter implements GatewayFilter {
private static final Log log = LogFactory.getLog(CacheFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//ServerHttpRequest request = exchange.getRequest();
//if (Cache.exists(request.getBody(),request.getPath(),request.getQueryParams())) {
//String reponseBody = Cache.get(request.getBody(),request.getPath(),request.getQueryParams());
String reponseBody = "test cache";
// The response is not mutated?
exchange.mutate().response(changeResponseBody(exchange,reponseBody)).build();
exchange.getResponse().setStatusCode(HttpStatus.OK);
return exchange.getResponse().setComplete();
//}
//return chain.filter(exchange);
}
public ServerHttpResponseDecorator changeResponseBody (ServerWebExchange exchange, String reponseBody) {
ServerHttpResponse originalResponse = exchange.getResponse();
ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator (originalResponse);
byte[] bytes = reponseBody.getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
responseDecorator.writeWith(Flux.just(buffer));
return responseDecorator;
}
}
What is not working?
In the response I receive the suitable status code (200 in this case, but also tested with others) but the body is empty. In this case I am trying to build "test cache" in the body. It seems that the mutation is not working. Maybe something is wrong with changeResponseBody.
@esacaceres , I'm also facing the same issue. Did you find a workaround for this?. If so, can you share.
The main problem with cache is that is a blocking operation. Since, Spring Cloud Gateway is based Reactor project it needs a cache non-blocking (see RxCache). Currently there is not an official support.
I created 2 ServerHttpResponseDecorator instances one to do the actual job and another one to use cached data and it works.
I need to refactor and clean up the code but I'll paste a part of it here:
if(cachedResponse.isEmpty()) {
return setPathFilter.filter(exchange.mutate().response(responseDecorator).build(), chain);
}
return chain.filter(exchange.mutate().response(cacheDecorator).build());
hope this helps
That way I was able to write response body, using writeWith on return:
override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
val responseBody = "{ \"test\":\"test response\"}"
exchange.response.statusCode = HttpStatus.CREATED
exchange.response.headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
return exchange.response.writeWith(Flux.just(exchange.response.bufferFactory().wrap(responseBody.toByteArray())))
}
The upstairs method does work! Thx!!!
That way I was able to write response body, using writeWith on return:
override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> { val responseBody = "{ \"test\":\"test response\"}" exchange.response.statusCode = HttpStatus.CREATED exchange.response.headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) return exchange.response.writeWith(Flux.just(exchange.response.bufferFactory().wrap(responseBody.toByteArray()))) }
Most helpful comment
I created 2
ServerHttpResponseDecoratorinstances one to do the actual job and another one to use cached data and it works.I need to refactor and clean up the code but I'll paste a part of it here:
hope this helps