Get request body string from ServerHttpRequest / Flux<DataBuffer>

纵饮孤独 提交于 2021-01-27 11:45:27

问题


I am using spring boot version - 2.0.6.RELEASE and spring cloud version - Finchley.SR2

and i have created my custom gateway filter to modify the request body.

but while converting the request body to string using Flux i am getting a empty string. i need a method to get the string corresponding to my request body.

@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();

}

回答1:


You could use the ModifyRequestBodyGatewayFilterFactory which I believe is included in Spring Cloud Gateway 2.0.2 which is part of Finchley.

For 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);
    };
}



回答2:


This is another approach work in spring cloud gateway 2.2.5, we will use ReadBodyPredicateFactory, as this will cache requestBody to ServerWebExchange with attribute key cachedRequestBodyObject

create always true Predicate

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

in application.yml, add Predicate

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

in your own filter, get requestBody like below:

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

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

        };
    }



回答3:


once you read(log by reading) the request body, request drops there itself. spring cloud gateway needs to record the contents of the request body, but the request body can only be read once. If the request body is not encapsulated after reading it , the latter service will not be able to read the body data. follow this




回答4:


Refinement of @tony.hokan answer https://stackoverflow.com/a/64080867/1484823 using spring cloud gateway rewrite body request to save the request body (and possibly response body) as an attribute of the 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();
    }

in your own filter, get requestBody like below:

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

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

        };
    }


来源:https://stackoverflow.com/questions/57562873/get-request-body-string-from-serverhttprequest-fluxdatabuffer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!