spring-cloud / spring-cloud/spring-cloud-gateway

Read resposeBody

Open
#3,941 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

waiting-for-triage
Dominant language
Java
Stars
4.9k
Forks
3.5k
Avg merge
20h 57m
Merged PRs (30d)
8

Description

Why isn't there a standardized and simple way to access the responseBody of a response from a GlobalFilter? .

I want to log the responseBody but using ServerHttpResponseDecorator the order logic is not executed properly.

Is this related to the framework's responsibilities? Something like: the gateway shouldn't have access to the response body.

`
@Component
@Slf4j
public class GlobalPostLoggingFilter implements GlobalFilter, Ordered {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    return doFilter(exchange, chain);
}

@Override
public int getOrder() {
    return 4;
}

private Mono<Void> doFilter(ServerWebExchange exchange, GatewayFilterChain chain) {
    ServerHttpResponse response = exchange.getResponse();
    DataBufferFactory dataBufferFactory = response.bufferFactory();
    ServerHttpResponseDecorator decoratedResponse = getDecoratedResponse(response, dataBufferFactory);
    return chain.filter(exchange.mutate().response(decoratedResponse).build())
            .doOnSuccess(s -> {
                MDC.put("responseCookies", responseCookies(exchange));
                MDC.put("responseStatus", responseStatus(exchange));
                MDC.put("responseHeaders", responseHeaders(exchange));
                log.info("Sucesso ao executar Gateway forwarding.");
            })
            .doFinally(s -> MDC.clear());
}

private ServerHttpResponseDecorator getDecoratedResponse(ServerHttpResponse response,
                                                         DataBufferFactory dataBufferFactory) {
    return new ServerHttpResponseDecorator(response) {
        @Override
        public Mono<Void> writeWith(final Publisher<? extends DataBuffer> body) {
            if (body instanceof Flux) {
                Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                    DefaultDataBuffer joinedBuffers = new DefaultDataBufferFactory().join(dataBuffers);
                    byte[] content = new byte[joinedBuffers.readableByteCount()];
                    joinedBuffers.read(content);
                    String responseBody = new String(content, StandardCharsets.UTF_8);

                    MDC.put("responseBody", responseBody);

                    return dataBufferFactory.wrap(responseBody.getBytes());
                }));
            }
            return super.writeWith(body);
        }
    };
}

}`

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No repository file or test is named. Start by tracing the GlobalFilter and ServerHttpResponseDecorator example, especially writeWith and the response-body buffering behavior, then determine whether the framework should define a supported access path. Done would require an agreed scope and tests for the standardized response-body behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring, spring-boot
Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.