Spring Cloud gateway отправляет ответ в фильтре - PullRequest
3 голосов
/ 11 января 2020

Я использую Spring Cloud Gateway в качестве пограничного сервера. Это поток

Если у запроса есть заголовок с именем '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, присутствует введенный заголовок в ответ, но данные не доступны в ответ.

1 Ответ

0 голосов
/ 04 февраля 2020

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

  • Используйте flatMap вместо doOnSuccess
  • , не используйте then или switchIfEmpty, вместо этого используйте onErrorResume
  • Return response.writeWith

    @ Component @ Slf4j publi c класс FooFilter реализует 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));
    }
    

    }

...