Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to modify the response body in Spring Cloud Gateway just before the commit

I'm using Spring Cloud Gateway with Spring 5, Spring Reactor and Netty for a project. For every request send to the gateway I want to do something just before the response is sent to the client. The best way I have found to do it is to add an action to the response with the beforeCommit method.

I first tried this approach :

        exchange.getResponse().beforeCommit(() -> {
            ServerHttpResponse response = exchange.getResponse();
            try {
                myActionDoneHere();
                response.setStatusCode(OK);
                return Mono.empty();
            } catch (Exception ex) {
                return Mono.error(new MyException(ex));
            }
        });

And tried to handle the exception in an exception handler :

public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
    if (isMyException(ex)) {
     exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
        exchange.getResponse().getHeaders().setContentLength(MSG.length());
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
        return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(MSG.getBytes())));
    }

    return Mono.error(ex);
}

When I do that I have an exception when I try to modify the content length. If I understand well the situation. I can't modify the response anymore in my handler because the it as been already committed. So I tried an other solution and tried to modify the response in my action executed just before the commit :

exchange.getResponse().beforeCommit(() -> {
    ServerHttpResponse response = exchange.getResponse();
    try {
        myActionDoneHere();
        response.setStatusCode(OK);
        return Mono.empty();
    } catch (Exception ex) {
        response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
        response.getHeaders().setContentLength(MSG.length());
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
        return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(MSG.getBytes())));
    }
});

This time I don't have any exception, I can modify the content length but I can't modify the body of the response.

So does someone know if it's possible to do so and How ?

like image 967
Pit Avatar asked Apr 30 '18 13:04

Pit


People also ask

Which elements are used to build a routing rule in spring Cloud Gateway?

It is defined by an ID, a target URI, a collection of predicates (Predicate) and a collection of filters. If the predicate aggregation is judged to be true, the route is matched.

What is RewritePath in spring Cloud Gateway?

It is used to rewrite the incoming request URI path. The RewritePath GatewayFilter Factory takes a path regexp parameter and a replacement parameter. This uses Java regular expressions for a flexible way to rewrite the request path.

How do you implement filters in spring Cloud Gateway?

Implementing Spring Cloud Gateway Filters using Java Configuration. In the FirstController we extract the request header we have added in the pre filter and print it. In the SecondController we extract the request header we have added in the pre filter and print it. Run the application.


1 Answers

I used the technique that was inside WebClientWriteResponseFilter

    if (failedAuthorization) {
        ServerWebExchangeUtils.setResponseStatus(exchange, HttpStatus.UNAUTHORIZED);
        ServerWebExchangeUtils.setAlreadyRouted(exchange);
        final Map<String, String> error = Map.of("error", "unauthorized");
        return chain.filter(exchange).then(Mono.defer(() -> {
            final ServerHttpResponse response = exchange.getResponse();
            response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8.toString());
            return response.writeWith(new Jackson2JsonEncoder().encode(Mono.just(error),
                response.bufferFactory(),
                ResolvableType.forInstance(error),
                MediaType.APPLICATION_JSON_UTF8,
                Hints.from(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix()))
            );
        }));
    }
like image 98
Archimedes Trajano Avatar answered Sep 27 '22 21:09

Archimedes Trajano