Pare de Criar Filtros Manuais: Otimize seu Spring Cloud Gateway com Recursos Nativos

A Armadilha do Excesso de Código Customizado em Gateways

Muitas equipes de desenvolvimento, ao implementar um API Gateway, cometem o erro de criar filtros customizados para funcionalidades que já existem nativamente no framework. Esse hábito transforma problemas de configuração em problemas de manutenção de código, aumentendo a complexidade técnica e o débito técnico do projeto.

O Spring Cloud Gateway oferece mais de 30 fábricas de filtros (GatewayFilter Factories) e diversos filtros globais que cobrem desde a manipulação de headers e reescrita de caminhos até mecanismos complexos de rate limiting, circuit breaker e retentativas. Ao entender e utilizar esses recursos, é possível reduzir em até 80% o código boilerplate do gateway.

Arquitetura e Ciclo de Vida da Requisição

Para utilizar o Spring Cloud Gateway de forma eficiente, é fundamental compreender como ele processa cada requisição. O fluxo segue uma sequência lógica baseada em Programação Reativa (Project Reactor):

  1. RoutePredicateHandlerMapping: Identifica se a requisição atual corresponde a alguma rota configurada com base em predicados (Path, Host, Method, etc.).
  2. FilteringWebHandler: Combina os filtros específicos da rota com os filtros globais e os ordena.
  3. Cadeia de Filtros (Pre-phase): Executa a lógica antes de encaminhar a requisição ao serviço de destino.
  4. NettyRoutingFilter: Realiza o encaminhamento da requisição para o microserviço downstream usando o cliente HTTP do Netty.
  5. Cadeia de Filtros (Post-phase): Executa a lógica de retorno, processando a resposta antes de enviá-la ao cliente final.

Modelo Não-Bloqueante

Diferente do antigo Zuul 1.x, o Spring Cloud Gateway roda sobre o Spring WebFlux e o Reactor Netty. Isso significa que ele utiliza um modelo de Event Loop, onde poucas threads processam milhares de conexões simultâneas. Regra de ouro: Nunca execute operações bloqueantes (como JDBC ou Thread.sleep()) dentro de um filtro, sob risco de travar todo o gateway.

Categorias de Filtros Nativos Essenciais

Em vez de decorar todos os filtros, é mais produtivo classificá-los por sua responsabilidade funcional:

1. Manipulação de Protocolo e Cabeçalhos

Utilizados para higienizar requisições externas e propagar contextos de identidade ou rastreamento para os serviços internos.

  • AddRequestHeader / SetRequestHeader: Adiciona ou sobrescreve informações no cabeçalho.
  • RemoveResponseHeader: Remove cabeçalhos sensíveis do serviço downstream antes de responder ao cliente.
  • DedupeResponseHeader: Remove cabeçalhos duplicados (comum em problemas de CORS).

2. Reescrita de Caminhos (Path Transformation)

Permite desacoplar a URL pública da estrutura interna de APIs dos microserviços.

spring:
  cloud:
    gateway:
      routes:
        - id: servico_estoque
          uri: lb://inventory-service
          predicates:
            - Path=/v1/estoque/**
          filters:
            - StripPrefix=1
            - AddRequestHeader=X-Origin-Gateway, SCG-Production

No exemplo acima, uma requisição para /v1/estoque/produtos é encaminhada para o serviço de inventário como /produtos, removendo o prefixo inicial.

3. Resiliência e Estabilidade

Filtros que protegem o ecossistema de falhas em cascata e picos de tráfego.

  • RequestRateLimiter: Implementa controle de vazão (geralmente via Redis com algoritmo Token Bucket).
  • Retry: Configura tentativas automáticas em caso de falhas específicas (ex: 503 Service Unavailable).
  • CircuitBreaker: Integração com Resilience4j para interromper chamadas a serviços instáveis.

Implementando Lógica Customizada (Apenas quando necessário)

Quando a lógica de negócio exige uma validação que não pode ser resolvida via configuração, devemos implementar um GatewayFilterFactory ou um GlobalFilter. Abaixo, um exemplo de um filtro que monitora o tempo de processamento sem bloquear a thread:

@Component
public class MonitoramentoTempoFilter implements GlobalFilter, Ordered {

    private static final String START_TIME_ATTR = "startTimeMillis";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // Fase PRE: Armazena o timestamp inicial
        exchange.getAttributes().put(START_TIME_ATTR, System.currentTimeMillis());

        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            // Fase POST: Calcula a diferença e adiciona no log ou header
            Long startTime = exchange.getAttribute(START_TIME_ATTR);
            if (startTime != null) {
                long duration = System.currentTimeMillis() - startTime;
                exchange.getResponse().getHeaders().add("X-Processing-Duration-MS", String.valueOf(duration));
            }
        }));
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}

Diferenças entre GatewayFilter e GlobalFilter

A escolha entre o tipo de filtro impacta diretamente no escopo de atuação:

Tipo Escopo Uso Recomendado
GatewayFilter Rota Específica Transformações de payload ou headers exclusivas de um microserviço.
default-filters Todas as Rotas via YAML Políticas globais de segurança (ex: SecureHeaders) aplicadas via config.
GlobalFilter Todas as Rotas via Código Autenticação cantralizada, logging de auditoria e tracing.

Melhores Práticas para o Ambiente Produtivo

Para manter um gateway saudável e de alta performance, siga estas diretrizes:

  • Priorize Configuração: Se existe um filtro nativo (como RewritePath), utilize-o em vez de criar um filtro Java.
  • Evite Log de Body: Ler o corpo da requisição/resposta (Request/Response Body) exige carregar os dados em memória, o que pode causar overhead e problemas de GC em alta carga.
  • Gestão de Erros: Utilize o filtro FallbackHeaders em conjunto com CircuitBreaker para fornecer respostas amigáveis ao cliente quando o back end falhar.
  • Observabilidade: Aproveite a integração nativa com Micrometer para expor métricas de latência e taxa de erro por rota.

Tags: Spring Cloud Gateway Spring WebFlux microservices java API Gateway

Publicado em 8-18 20:13