【问题标题】:Get request body string from ServerHttpRequest / Flux<DataBuffer>从 ServerHttpRequest / Flux<DataBuffer> 获取请求正文字符串
【发布时间】:2019-12-25 00:51:00
【问题描述】:

我使用的是 spring boot 版本 - 2.0.6.RELEASE 和 spring cloud 版本 - 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();

}

【问题讨论】:

    标签: java spring-cloud spring-cloud-gateway


    【解决方案1】:

    细化@tony.hokan answer https://stackoverflow.com/a/64080867/1484823 使用spring cloud gateway rewrite body request 将请求正文(可能还有响应正文)保存为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");
    
            };
        }
    

    【讨论】:

    • 您为我节省了大量时间和研究。非常感谢。你是英雄。
    【解决方案2】:

    这是 spring cloud gateway 2.2.5 中的另一种方法,我们将使用 ReadBodyPredicateFactory,因为这将使用属性键 cachedRequestBodyObject 将 requestBody 缓存到 ServerWebExchange

    创建始终为真的谓词

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

    在application.yml中,添加谓词

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

    【讨论】:

      【解决方案3】:

      您可以使用 ModifyRequestBodyGatewayFilterFactory,我相信它包含在 Spring Cloud Gateway 2.0.2 中,它是 Finchley 的一部分。

      例如:

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

      【讨论】:

        【解决方案4】:

        一旦您阅读(通过阅读记录)请求正文,请求就会自行删除。 spring cloud gateway需要记录请求体的内容,但是请求体只能读取一次。如果请求body读取后没有封装,后面的服务将无法读取body数据。 follow this

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-06-13
          • 2019-06-08
          • 2021-05-18
          • 1970-01-01
          • 2021-12-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多