简体   繁体   English

如何在 Spring 云网关(Webflux)后过滤器中获取原始响应正文

[英]How to get Original response body in Spring cloud gateway (Webflux) Post filter

I've implemented a Post filter in the spring cloud gateway.我已经在 spring 云网关中实现了一个 Post 过滤器。 But I need the readable format (JSON Format of response body) before sending it to UI.但在将其发送到 UI 之前,我需要可读格式(响应正文的 JSON 格式)。 I'm getting exchange.getResponse().我得到了 exchange.getResponse()。 (when i printed in console: org.springframework.http.server.reactive.ReactorServerHttpResponse@3891d61a ) But it is in the reactive object. (当我在控制台中打印时: org.springframework.http.server.reactive.ReactorServerHttpResponse@3891d61a )但它在反应对象中。 I can't able to see the actual original response which is coming from API to post filter.我无法看到来自 API 到后过滤器的实际原始响应。 I've searched numerous stackoverflow topics but couldn't get an actual solution.我搜索了许多 stackoverflow 主题,但找不到实际的解决方案。 Please assist...请协助...

you can extract/read/modify/manipulate the request and response and their headers with the help of ServerHttpRequestDecorator & ServerHttpResponseDecorator see below您可以在ServerHttpRequestDecoratorServerHttpResponseDecorator的帮助下提取/读取/修改/操作请求和响应及其标头,见下文

Note: i implemented GatewayFilter because i have this logic in gateway service level, if you want to modify at micro service level you can use WebFilter注意:我实现了 GatewayFilter因为我在网关服务级别有这个逻辑,如果你想在微服务级别进行修改,你可以使用WebFilter

import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.IOUtils;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DefaultDataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.io.ByteArrayOutputStream;
import java.nio.channels.Channels;
import java.nio.charset.StandardCharsets;

@Configuration
@Log4j2
public class RequestResponseModifyFilter implements GatewayFilter/WebFilter, Ordered {


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

        String path = exchange.getRequest().getPath().toString();
        ServerHttpResponse response = exchange.getResponse();
        ServerHttpRequest request = exchange.getRequest();
        DataBufferFactory dataBufferFactory = response.bufferFactory();

        // log the request body
        ServerHttpRequest decoratedRequest = getDecoratedRequest(request);
        // log the response body
        ServerHttpResponseDecorator decoratedResponse = getDecoratedResponse(path, response, request, dataBufferFactory);
        return chain.filter(exchange.mutate().request(decoratedRequest).response(decoratedResponse).build());
    }

    private ServerHttpResponseDecorator getDecoratedResponse(String path, ServerHttpResponse response, ServerHttpRequest request, 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);//MODIFY RESPONSE and Return the Modified response
                        log.debug("requestId: {}, method: {}, url: {}, \nresponse body :{}", request.getId(), request.getMethodValue(), request.getURI(), responseBody);

                        return dataBufferFactory.wrap(responseBody.getBytes());
                    })).onErrorResume(err -> {

                        log.error("error while decorating Response: {}",err.getMessage());
                        return Mono.empty();
                    });

                }
                return super.writeWith(body);
            }
        };
    }

    private ServerHttpRequest getDecoratedRequest(ServerHttpRequest request) {

        return new ServerHttpRequestDecorator(request) {
            @Override
            public Flux<DataBuffer> getBody() {

                log.debug("requestId: {}, method: {} , url: {}", request.getId(), request.getMethodValue(), request.getURI());
                return super.getBody().publishOn(Schedulers.boundedElastic()).doOnNext(dataBuffer -> {

                    try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {

                        Channels.newChannel(byteArrayOutputStream).write(dataBuffer.asByteBuffer().asReadOnlyBuffer());
                        String requestBody = IOUtils.toString(byteArrayOutputStream.toByteArray(), StandardCharsets.UTF_8.toString());//MODIFY REQUEST and Return the Modified request
                        log.debug("for requestId: {}, request body :{}", request.getId(), requestBody);
                    } catch (Exception e) {
                        log.error(e.getMessage());
                    }
                });
            }
        };
    }

    @Override
    public int getOrder() { return -2;}
}

https://github.com/einsteinarbert/spring-webfux-response-logging注意安全链,也许那个过滤器会覆盖你的过滤器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 您如何在 Spring Cloud Gateway (Webflux) POST 过滤器中读取响应正文 - How do you read response body in Spring Cloud Gateway (Webflux) POST filter Spring 云网关 - 如何修改后过滤器中的响应正文 - Spring Cloud Gateway - How To Modify Response Body In Post Filter 如何在 Spring Gateway 中获取响应体 - How to get response body in Spring Gateway 在 Spring Cloud Gateway 过滤器中提取 WebClient GET 响应值 - Extract WebClient GET response values within a Spring Cloud Gateway filter Spring Cloud Gateway:修改后的响应体被截断 - Spring Cloud Gateway: Modified Response Body is Truncated 如何在 Zuul 后置过滤器中获取响应正文? - How to get response body in Zuul post filter? 如何在 Spring WebFlux 的响应体中流式传输二进制数据 - How to stream binary data in a response body in Spring WebFlux 如何从 Spring Boot 过滤器中的 servletResponse 获取响应正文 - How to get Response Body from servletResponse in Spring Boot Filter 我们如何在 Spring 引导过滤器中获取和设置响应主体 - How can we get and set response body in Spring Boot Filter 在WebFlux WebClient中测试状态代码时如何获取响应体? - How to get response body when testing the status code in WebFlux WebClient?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM