【问题标题】:How to set request body in GatewayFilter with Spring Cloud Gateway如何使用 Spring Cloud Gateway 在 GatewayFilter 中设置请求正文
【发布时间】:2021-10-14 21:05:58
【问题描述】:

我有一个 GatewayFilter。它接收一个请求,

  1. 首先检查签名(代码省略)
  2. 查询一些需要的参数
  3. 将它们添加到请求中
  4. 最终转发请求

如何将查询参数作为 json 添加到请求正文中?

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)  {
        ServerHttpResponse response = exchange.getResponse();
        ServerHttpRequest request = exchange.getRequest();



        BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = getBodyInsert(exchange);
        CachedBodyOutputMessage outputMessage = getCachedBodyOutputMessage(exchange);
        
        return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
           //1.checks the signature  (omit)
    
            //2. get these parameters remotely
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("calcPackageId", 10000);
            paramMap.put("userId", 10001);
            paramMap.put("barId", 10002);
            String body = JSON.toJSON(paramMap);
            //3. todo how to set request body {"calcPackageId":"10000","barId":"10002","userId":"10001"} ??????

          //4 forwards the request
            return chain.filter(exchange.mutate().request(newRequest).build());
        }));
    }



   //not important

    private BodyInserter<Mono<String>, ReactiveHttpOutputMessage> getBodyInsert(ServerWebExchange exchange) {
        ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders);
        Mono<String> rawBody = serverRequest.bodyToMono(String.class).map(s -> s);
        return BodyInserters.fromPublisher(rawBody, String.class);

    }

    private CachedBodyOutputMessage getCachedBodyOutputMessage(ServerWebExchange exchange) {
        HttpHeaders tempHeaders = new HttpHeaders();
        tempHeaders.putAll(exchange.getRequest().getHeaders());
        tempHeaders.remove(HttpHeaders.CONTENT_LENGTH);
        return new CachedBodyOutputMessage(exchange, tempHeaders);
    }

【问题讨论】:

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


    【解决方案1】:

    一种方法是将ModifyRequestBodyGatewayFilterFactory bean 注入您的过滤器。它由 Spring Cloud Gateway 的 Autoconfig 自动初始化。

    然后,对于它的.apply 方法,您可以传递一个RewriteFunction 对象。有了这个,您可以创建一个实现RewriteFunction 接口的自定义类,使用您需要的数据对其进行初始化,然后将其作为新主体返回。例如:

    public class SomeFilter implements GatewayFilter {
    
        private final ModifyRequestBodyGatewayFilterFactory factory;
    
        public SomeFilter(ModifyRequestBodyGatewayFilterFactory factory) {
            this.factory = factory;
        }
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            Map<String, Integer> someMap = new HashMap<>();
            someMap.put("AbC", 100);
    
            ModifyRequestBodyGatewayFilterFactory.Config cfg = new ModifyRequestBodyGatewayFilterFactory.Config();
            cfg.setRewriteFunction(String.class, String.class, new SomeRewriteFunction(someMap));
    
            GatewayFilter modifyBodyFilter = factory.apply(cfg);
    
            return modifyBodyFilter.filter(exchange, ch -> Mono.empty())
                    .then(chain.filter(exchange));
        }
    }
    

    和重写功能:

    public class SomeRewriteFunction implements RewriteFunction<String, String> {
    
        private final Map<String, Integer> values;
    
        public SomeRewriteFunction(Map<String, Integer> values) {
            this.values = values;
        }
    
        @Override
        public Publisher<String> apply(ServerWebExchange serverWebExchange, String oldBody) {
            /* do things here */
            /* example: */
            try {
                String newBody = new ObjectMapper().writeValueAsString(values);
                return Mono.just(newBody);
            } catch (Exception e) {
                /* error parsing values to json, do something else */
                return Mono.just(oldBody);
            }
        }
    }
    

    其他方法是注入一个装饰器,然后修改其getBody()方法:

    public class SomeFilter implements GatewayFilter {
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            Map<String, Integer> someMap = new HashMap<>();
            someMap.put("AbC", 100);
    
            SomeDecorator requestDecorator = new SomeDecorator(exchange.getRequest(), someMap);
    
            return chain.filter(exchange.mutate().request(requestDecorator).build());
        }
    }
    

    和装饰者:

    public class SomeDecorator extends ServerHttpRequestDecorator {
    
        private final Map<String, Integer> values;
    
        public SomeDecorator(ServerHttpRequest delegate, Map<String, Integer> values) {
            super(delegate);
            this.values = values;
        }
    
        @Override
        public Flux<DataBuffer> getBody() {
    
            try {
                String newBody = new ObjectMapper().writeValueAsString(values);
                DefaultDataBufferFactory factory = new DefaultDataBufferFactory();
                DefaultDataBuffer buffer = factory.wrap(newBody.getBytes());
                return Flux.just(buffer);
            } catch (JsonProcessingException e) {
                return super.getBody();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-11-14
      • 1970-01-01
      • 2019-03-31
      • 2020-11-27
      • 2020-01-14
      • 2020-04-30
      • 1970-01-01
      • 2018-12-18
      • 2020-03-10
      相关资源
      最近更新 更多