Ответ на отправку шлюза Spring Cloud в фильтре

Я использую облачный шлюз Spring в качестве пограничного сервера. Это поток

Если запрос имеет заголовок с именем «x-foo», найдите значение заголовка, получите строку с другого сервера и отправьте эту строку в качестве ответа вместо фактического проксирования запроса.

Вот код для фильтра DSL

@Bean
    public RouteLocator routes(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("foo-filter", r -> r.header('x-foo').and().header("x-intercepted").negate()
                        .filters(f -> f.filter(fooFilter))
                        .uri("http://localhost:8081")) // 8081 is self port, there are other proxy related configurations too
                .build();
    }

Код для фильтра Foo

@Component
@Slf4j
public class FooFilter implements GatewayFilter {

    @Autowired
    private ReactiveRedisOperations<String, String> redisOps;

    @Value("${header-name}")
    private String headerName;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        var foo = request.getHeaders().getFirst(headerName);

        return redisOps.opsForHash()
                .get("foo:" + foo, "response")
                .doOnSuccess(s -> {
                    log.info("data on success");
                    log.info(s.toString()); // I am getting proper response here
                    if (s != null) {
                        ServerHttpResponse response = exchange.getResponse();
                        response.setStatusCode(HttpStatus.OK);
                        response.getHeaders().set("x-intercepted", "true");

                        byte[] bytes = s.toString().getBytes(StandardCharsets.UTF_8);

                        DataBuffer buffer = response.bufferFactory().wrap(bytes);

                        response.writeWith(Mono.just(buffer));

                        response.setComplete();
                    }
                })
                .then(chain.filter(exchange));
    }

}

Проблема в том, что ответ имеет правильный код 200, введенный заголовок присутствует в ответе, но данные недоступны в ответе.


person Akshay    schedule 11.01.2020    source источник
comment
Этот ответ, похоже, связан с вашим вопросом.   -  person Gaurav Agarwal    schedule 16.01.2020
comment
Именно то, что мне нужно.   -  person Akshay    schedule 16.01.2020
comment
Однако это дает мне ошибку после возврата. java.lang.UnsupportedOperationException: null в org.springframework.http.ReadOnlyHttpHeaders.putAll (ReadOnlyHttpHeaders.java:131) ~ [spring-web-5.2.2.RELEASE.jar: 5.2.2.RELEASE] Подавлено: response.core. publisher.FluxOnAssembly $ OnAssemblyException: ошибка обнаружена на следующих сайтах: | _ checkpoint? org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain] | _ контрольная точка? org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain]   -  person Akshay    schedule 16.01.2020
comment
Привет @Akshay, поделитесь обновленным кодом с помощью stacktrace   -  person Patel Romil    schedule 20.01.2020
comment
Видимо я использовал switchIfEmpty и это был случай досрочного исполнения.   -  person Akshay    schedule 04.02.2020


Ответы (1)


Вот так я начал работать.

  • Используйте flatMap вместо doOnSuccess
  • не используйте then или switchIfEmpty вместо этого используйте onErrorResume
  • Верните response.writeWith
    @Component
    @Slf4j
    public class FooFilter implements GatewayFilter {
    
        @Autowired
        private ReactiveRedisOperations<String, String> redisOps;
    
        @Value("${header-name}")
        private String headerName;
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            ServerHttpRequest request = exchange.getRequest();
            var foo = request.getHeaders().getFirst(headerName);
    
            return redisOps.opsForHash()
                    .get("foo:" + foo, "response")
                    .flatMap(s -> {
                        log.info("data on success");
                        log.info(s.toString()); // I am getting proper response here
                        if (s != null) {
                            ServerHttpResponse response = exchange.getResponse();
                            response.setStatusCode(HttpStatus.OK);
                            response.getHeaders().set("x-intercepted", "true");
    
                            byte[] bytes = s.toString().getBytes(StandardCharsets.UTF_8);
    
                            DataBuffer buffer = response.bufferFactory().wrap(bytes);
    
                            return response.writeWith(Mono.just(buffer));
   
                        }else{ return chain.filter(exchange).then(Mono.fromRunnable(() -> {log.info("It was empty")} }
                    })
                    .onErrorResume(chain.filter(exchange));
        }
    }
person Akshay    schedule 04.02.2020