简体   繁体   English

在 spring 引导网关中拦截 Http 请求正文

[英]Intercept Http Request body in spring boot gateway

We are running a bunch of microservices which are guarded by a central gateway (org.springframework.cloud:spring-cloud-starter-gateway:2.1.0) that routes requests to the responsible microservice behind it.我们正在运行一组由中央网关(org.springframework.cloud:spring-cloud-starter-gateway:2.1.0)保护的微服务,该网关将请求路由到其背后的负责微服务。

We now want to add a service, that shall get the importent parts of each request as copy (like headers, request path, request body...) via a restful interface for tracking / statistic reasons.我们现在要添加一个服务,该服务将通过一个用于跟踪/统计原因的 RESTful 接口将每个请求的重要部分作为副本(如标头、请求路径、请求正文...)获取。 To have the code for this only at one place, we want to add it directly to the gateway service.为了只在一个地方有这个代码,我们想将它直接添加到网关服务中。

Implementing WebFilter seems to be a good start for this, but I'm having problems with the request body which is Flux<DataBuffer> .实现 WebFilter 似乎是一个好的开始,但我遇到了请求正文Flux<DataBuffer>的问题。

Subscribing to it causes an error: Only one connection receive subscriber allowed.订阅它会导致错误: Only one connection receive subscriber allowed. , because it's a unicast which prohibits multiple receivers of the content. ,因为它是禁止内容的多个接收者的单播。

@Slf4j
@Configuration
public class InterceptConfig implements WebFilter {

    private final StatisticServiceProperties properties;

    @Autowired
    public InterceptConfig(StatisticServiceProperties properties) {
        this.properties = properties;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        log.debug("request intercepted. sending to statistic service : " + request.getURI().toString());

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        request.getBody().subscribe(dataBuffer -> {
            try {
                byteArrayOutputStream.write(dataBuffer.asInputStream().readAllBytes());
            } catch (IOException e) {
                log.debug("couldn't extract body from request", e);
            }
        });

        new StatisticServiceClient(
                new RestTemplate(),
                properties.getBaseUrl() + "/statistic"
        ).createStatistic(
                new CreateStatisticRequest(
                        new Date(),
                        request.getURI(),
                        request.getHeaders(),
                        byteArrayOutputStream.toByteArray()
                )
        );
        return chain.filter(exchange);
    }
}

Is there a way to get the content of the request body without breaking the application?有没有办法在不破坏应用程序的情况下获取请求正文的内容?

Edit: 18.11.2019编辑:18.11.2019

I found a solution that solves this for me: https://github.com/spring-cloud/spring-cloud-gateway/issues/747#issuecomment-451805283我找到了一个为我解决这个问题的解决方案: https://github.com/spring-cloud/spring-cloud-gateway/issues/747#issuecomment-451805283

This is not tested code but try to create ConnectableFlux from original flux.这不是经过测试的代码,而是尝试从原始通量创建ConnectableFlux That should allow multiple subscribers:这应该允许多个订阅者:

Flux<DataBuffer> connFlux = request.getBody().share();
Flux.from(connFlux).subscribe(dataBuffer -> {
            try {
                byteArrayOutputStream.write(dataBuffer.asInputStream().readAllBytes());
            } catch (IOException e) {
                log.debug("couldn't extract body from request", e);
            }
        });

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM