spring:
cloud:
gateway:
routes:
- id: rota_provedor
uri: http://localhost:8081
predicates:
- Path=/api/**
- id: rota_consumidor
uri: http://localhost:8082
predicates:
- Path=/cliente/**
No exemplo anterior, os endereços IP e porta estão fixos na configuração de URI, o que significa que as solicitações serão direcionadas para um nó específico. Em cenários com múltiplas instâncias, esta abordagem apresenta limitações, pois não permite balanceamento de carga automático.
Conexão com Múltiplas Instâncias
Para resolver este problema, podemos substituir o endereço fixo pelo nome do serviço registrado no service discovery. Considere que a porta 8081 corresponde ao serviço denominado servico-teste-provedor, enquanto a porta 8082 representa servico-teste-consumidor. A modificação necessária é a seguinte:
- id: rota_provedor
uri: lb://servico-teste-provedor
predicates:
- Path=/api/**
- id: rota_consumidor
uri: lb://servico-teste-consumidor
predicates:
- Path=/cliente/**
O prefixo lb:// indica que o gateway deve utilizar balanceamento de carga para resolver dinamicamente as instâncias disponíveis do serviço.
Predicados Disponíveis
Os predicados permitem adicionar condições adicionais às rotas. Mesmo que a URL corresponda ao padrão definido, a requisição só será processada se todas as condições forem satisfeitas. O Spring Cloud Gateway oferece diversas implementações nativas.
Predicados Temporais
Os predicados baseados em tempo verificam o momento em que a requisição é recebida:
- Before: aceita requisições antes de um horário específico
- After: aceita requisições após um horário específico
- Between: aceita requisições dentro de um intervalo de tempo
O formato utiliza ZonedDateTime, que inclui informações de fuso horário:
public static void main(String[] args) {
System.out.println(ZonedDateTime.now());
}
// Saída: 2024-11-20T15:30:45.123456789-03:00[America/Sao_Paulo]
Para um sistema de e-commerce com promoção relâmpago válida durante o dia 13 de julho de 2024:
- id: promocao_relampago
uri: lb://servico-teste-provedor
predicates:
- Path=/oferta/**
- Between=2024-07-13T00:00:00-03:00[America/Sao_Paulo],2024-07-14T00:00:00-03:00[America/Sao_Paulo]
Predicado de Cookie
Este predicado verifica a presença e valor de cookies na requisição:
- id: promocao_usuario_vip
uri: lb://servico-teste-provedor
predicates:
- Path=/oferta/**
- Between=2024-07-13T00:00:00-03:00[America/Sao_Paulo],2024-07-14T00:00:00-03:00[America/Sao_Paulo]
- Cookie=identificacao,joao.silva
A expressão joao.silva representa uma expressão regular que deve corresponder ao valor do cookie identificacao.
Predicado de Cabeçalho HTTP
Valida a existência e formato de headers específicos:
- id: promocao_usuario_vip
uri: lb://servico-teste-provedor
predicates:
- Path=/oferta/**
- Between=2024-07-13T00:00:00-03:00[America/Sao_Paulo],2024-07-14T00:00:00-03:00[America/Sao_Paulo]
- Cookie=identificacao,joao.silva
- Header=idade,[0-9]{2}
Predicados Adicionais
- Path: verifica se o caminho da URL coresponde ao padrão especificado
- Query: exige a presença de parâmetros de consulta na URL
- RemoteAddr: aplica restrições baseadas em endereço IP
- Method: limita o acesso a métodos HTTP específicos como GET, POST, PUT, DELETE
Criando Predicados Personalizados
Para requisitos específicos, podemos implementar predicados customizados estendendo AbstractRoutePredicateFactory:
@Component
public class ValidacaoNivelFactory extends AbstractRoutePredicateFactory<ValidacaoNivelFactory.Configuracao> {
public ValidacaoNivelFactory() {
super(ValidacaoNivelFactory.Configuracao.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList("nivelRequerido");
}
@Override
public Predicate<ServerWebExchange> apply(Configuracao config) {
return solicitacao -> {
MultiValueMap<String, String> parametros = solicitacao.getRequest().getQueryParams();
String nivel = parametros.getFirst("nivel");
if (!StringUtils.hasText(nivel)) {
return false;
}
return nivel.equals(config.getNivelRequerido());
};
}
@Validated
public static class Configuracao {
private String nivelRequerido;
public String getNivelRequerido() {
return nivelRequerido;
}
public void setNivelRequerido(@NotNull String nivelRequerido) {
this.nivelRequerido = nivelRequerido;
}
}
}
A convenção de nomenclatura exige que a classe termine com RoutePredicateFactory, sendo que a parte anterior define o nome curto utilizado nas configurações YAML.
Configuração da Rota Personalizada
routes:
- id: rota_provedor
uri: http://localhost:8081
predicates:
- Path=/api/**
- ValidacaoNivel=5
O valor 5 representa o nível mínimo necessário para que a requisição seja processada. A correspondência é feita com base na propriedade nivelRequerido definida na classe de configuração.
Validação
Para testar o predicado personalizado, basta incluir o parâmetro nivel=5 na URL de requisição. Caso o valor seja diferente ou ausente, a rota não será ativada.