Получить строку тела запроса от ServerHttpRequest / Flux ‹DataBuffer›

Я использую весеннюю загрузочную версию - 2.0.6.RELEASE и весеннюю облачную версию - Finchley.SR2

и я создал собственный фильтр шлюза, чтобы изменить тело запроса.

но при преобразовании тела запроса в строку с помощью Flux я получаю пустую строку. Мне нужен метод для получения строки, соответствующей моему телу запроса.

@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    ServerHttpRequest request = (ServerHttpRequest) exchange.getRequest();
    String s = resolveBodyFromRequest(request);
     /* s comes out to be "" */
    return chain.filter(newExchange);


}



private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest){
    //Get the request body
    Flux<DataBuffer> body = serverHttpRequest.getBody();
    StringBuilder sb = new StringBuilder();

    body.subscribe(buffer -> {
        byte[] bytes = new byte[buffer.readableByteCount()];
        buffer.read(bytes);
        DataBufferUtils.release(buffer);
        String bodyString = new String(bytes, StandardCharsets.UTF_8);
        sb.append(bodyString);
    });
    return sb.toString();

}

person bhavishya singh    schedule 19.08.2019    source источник


Ответы (4)


Вы можете использовать ModifyRequestBodyGatewayFilter, в который, по мнению IFC, включен is Spring Cloud Gateway 2.0.2, который является частью Finchley.

Для Ex:

@Override
public GatewayFilter apply(Config config) {
   return (exchange, chain) -> {
        ModifyRequestBodyGatewayFilterFactory.Config modifyRequestConfig = new ModifyRequestBodyGatewayFilterFactory.Config()
                .setContentType(ContentType.APPLICATION_JSON.getMimeType())
                .setRewriteFunction(String.class, String.class, (exchange1, originalRequestBody) -> {
                    String modifiedRequestBody = yourMethodToModifyRequestBody(originalRequestBody);
                    return Mono.just(modifiedRequestBody);
                });

        return new ModifyRequestBodyGatewayFilterFactory().apply(modifyRequestConfig).filter(exchange, chain);
    };
}
person Fabian    schedule 19.02.2020

Это еще один подход, работающий в весеннем облачном шлюзе 2.2.5, мы будем использовать ReadBodyPredicateFactory, так как это будет кэшировать requestBody в ServerWebExchange с ключом атрибута cachedRequestBodyObject

создать всегда истинный предикат

@Component
public class TestRequestBody implements Predicate
{
    @Override
    public boolean test(Object o)
    {
        return true;
    }
}

в application.yml добавьте Predicate

spring:
  cloud:
    gateway:
      routes:
       ....
          predicates:
            .....
            - name: ReadBodyPredicateFactory
              args:
                inClass: "#{T(String)}" 
                predicate: "#{@testRequestBody}"

в вашем собственном фильтре получите requestBody, как показано ниже:

    @Override
    public GatewayFilter apply(Object config)
    {
        return (exchange, chain) -> {

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

        };
    }
person tony.hokan    schedule 26.09.2020

как только вы прочитаете (зарегистрируете, прочитав) тело запроса, запрос будет сброшен туда сам. Облачный шлюз Spring должен записывать содержимое тела запроса, но тело запроса можно прочитать только один раз. Если тело запроса не инкапсулируется после его чтения, последняя служба не сможет прочитать данные тела. подписаться

person jbaddam17    schedule 26.08.2019

Уточнение ответа @ tony.hokan https://stackoverflow.com/a/64080867/1484823 с использованием тела перезаписи весеннего облачного шлюза запрос на сохранение тела запроса (и, возможно, тела ответа) как атрибут org.springframework.web.server.ServerWebExchange

    @Bean
    public RouteLocator myRouteSavingRequestBody(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("my-route-id",
                p -> p
                    .path("/v2/**") //your own path filter
                    .filters(f -> f
                        .modifyResponseBody(String.class, String.class,
                            (webExchange, originalBody) -> {
                                if (originalBody != null) {
                                    webExchange.getAttributes().put("cachedResponseBodyObject", originalBody);
                                    return Mono.just(originalBody);
                                } else {
                                    return Mono.empty();
                                }
                            })
                        .modifyRequestBody(String.class, String.class,
                            (webExchange, originalBody) -> {
                                if (originalBody != null) {
                                    webExchange.getAttributes().put("cachedRequestBodyObject", originalBody);
                                    return Mono.just(originalBody);
                                } else {
                                    return Mono.empty();
                                }
                            })

                    )
                    .uri("https://myuri.org")
            )
            .build();
    }

в вашем собственном фильтре получите requestBody, как показано ниже:

    @Override
    public GatewayFilter apply(Object config)
    {
        return (exchange, chain) -> {

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

        };
    }
person Guillaume Berche    schedule 26.10.2020
comment
Вы сэкономили мне много времени и исследований. Большое спасибо. Ты герой. - person riccardo.cardin; 04.01.2021