Как прочитать тело запроса с помощью весеннего webflux - PullRequest
0 голосов
/ 26 апреля 2018

Я использую Spring 5, Netty и Spring webflux для разработки и API Gateway. Иногда я хочу, чтобы шлюз остановил запрос, но я также хочу прочитать тело запроса, чтобы, например, зарегистрировать его и вернуть клиенту ошибку.

Я пытаюсь сделать это в WebFilter, подписавшись на тело.

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    if (enabled) {
        logger.debug("gateway is enabled. The Request is routed.");
        return chain.filter(exchange);
    } else {
        logger.debug("gateway is disabled. A 404 error is returned.");

        exchange.getRequest().getBody().subscribe();
        exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
        return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().allocateBuffer(0)));
    }
}

Когда я делаю это, это работает, когда содержание тела мало. Но когда у меня большой бобби, читается только первый элемент потока, поэтому я не могу получить все тело. Есть идеи как это сделать?

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

1.Добавить " readBody () " к почтовому маршруту:

builder.routes()
.route("get_route", r -> r.path("/**")
    .and().method("GET")
    .filters(f -> f.filter(myFilter))
    .uri(myUrl))
.route("post_route", r -> r.path("/**")
    .and().method("POST")
    .and().readBody(String.class, requestBody -> {return true;})
    .filters(f -> f.filter(myFilter))
    .uri(myUrl))

2. Затем вы можете получить строку тела в своем фильтре:

String body = exchange.getAttribute("cachedRequestBodyObject");

Преимущества:

  1. Без блокировки.

  2. Нет необходимости пополнять корпус для дальнейшего процесса.

Работает с Spring Boot 2.0.6.RELEASE + Sring Cloud Finchley.SR2 + Spring Cloud Gateway.

0 голосов
/ 26 апреля 2018

Проблема в том, что вы подписываетесь вручную в фильтре, что означает, что вы отключаете чтение запроса от остальной части конвейера. Вызов subscribe() дает вам Disposable, который помогает вам управлять базовым Subscription.

Таким образом, вам нужно соединить весь процесс как один конвейер, примерно так:

Flux<DataBuffer> requestBody = exchange.getRequest().getBody();
// decode the request body as a Mono or a Flux
Mono<String> decodedBody = decodeBody(requestBody); 
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
return decodedBody.doOnNext(s -> logger.info(s))
                  .then(exchange.getResponse().setComplete());

Обратите внимание, что декодирование всего тела запроса как Mono означает, что вашему шлюзу придется буферизовать все тело запроса в памяти.

DataBuffer специально является типом низкого уровня. Если вы хотите декодировать его (т. Е. Реализовать пример метода decodeBody) как строку, вы можете использовать одну из различных реализаций Decoder в Spring, например StringDecoder.

Теперь, поскольку это довольно большое и сложное пространство, вы можете использовать и / или взглянуть на Spring Cloud Gateway , который делает именно это и даже больше.

...