Spring-cloud-gateway: Cache

Created on 6 Apr 2018  路  7Comments  路  Source: spring-cloud/spring-cloud-gateway

Hello guys,

Is possible to add a filter to do caching based in a request and parameters?

  • If the request is cached then return the response. The response can be returned with exchange.getResponse().setComplete() in the filter but I found problems to modify the response body with my cached data.
@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;
    }
}


Most helpful comment

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

All 7 comments

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())))
    }
Was this page helpful?
0 / 5 - 0 ratings