Spring Cloud Gateway Complete Guide: Routes, Filters, and Rate Limiting with the Leaky Bucket Algorithm

Overview

A microservices gateway is a system that provides centralized authentication, security control, unified logging, monitoring, and rate limiting by exposing a single entry point.

Spring Cloud Gateway Workflow

  1. A client sends a request to Spring Cloud Gateway. The request is first extracted and assembled into a gateway context by HttpWebHandlerAdapter, which is then passed to DispatcherHandler.

  2. DispatcherHandler is the main request dispatcher. It routes requests to the appropriate handler, such as RoutePredicateHandlerMapping (the route predicate handler mapper).

  3. The route predicate handler mapper finds the matching route and returns the corresponding FilteringWebHandler.

  4. FilteringWebHandler builds and executes a filter chain. It then forwards the request to the backend proxy service. After the service processes the request, the response is returned to the Gateway client.

In the filter chain, filters are divided into Pre and Post types. All Pre filters execute before request is forwarded to the backend. After the backend service finishes processing, Post filters execute before the response is sent back.

Key concepts: Route, Predicate, Filter.

Gateway route configuration can be static (in application.yml) or dynamic (in code). Dynamic routing is more flexible. Below are examples of both.

Dynamic Path-Based Routing Configuration

Java Code Configuration

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("hailtaxi-driver", r -> r.path("/driver/**").uri("lb://hailtaxi-driver"))
        .route("hailtaxi-order", r -> r.path("/order/**").uri("lb://hailtaxi-order"))
        .route("hailtaxi-pay", r -> r.path("/pay/**").uri("lb://hailtaxi-pay"))
        .build();
}

Application.yml Configuration

spring:
  cloud:
    gateway:
      routes:
        - id: hailtaxi-driver
          uri: lb://hailtaxi-driver
          predicates:
            - Path=/driver/**
        - id: hailtaxi-order
          uri: lb://hailtaxi-order
          predicates:
            - Path=/order/**
        - id: hailtaxi-pay
          uri: lb://hailtaxi-pay
          predicates:
            - Path=/pay/**

Configuration parameters:

  • routes: Route definitions.
  • id: Unique identifier for the route.
  • uri: Target service address. Can be lb://IP:port or lb://${spring.application.name}.
  • predicates: Conditions for route matching (returns boolean). For example, Path=/driver/** matches all requests starting with /driver.
  • filters: Filters applied to matching requests. StripPrefix=1 removes the first path segment before forwarding.

Example: Using Cookie Predicate

The following configuration allows requests only if they contain a Cookie named username with value itheima.

gateway:
  routes:
    - id: hailtaxi-driver
      uri: lb://hailtaxi-driver
      predicates:
        - Path=/driver/**
        - Cookie=username,itheima

Example: Using Method Predicate

The following configuration matches only GET and POST requests.

gateway:
  routes:
    - id: hailtaxi-driver
      uri: lb://hailtaxi-driver
      predicates:
        - Path=/driver/**
        - Method=GET,POST

Filters

Classification

  • Default filters: Pre-built filters provided by the framework.
    • Global default filters: Apply to all routes.
    • Local default filters: Apply to specific routes.
  • Custom filters: Implemented by developers.
    • Global filters: Apply to all routes.
    • Local filters: Apply only to the configured route.

Common Default Filters

Filter Name Description Class Parent Class
AddRequestHeader Adds a header to the matching request AddRequestHeaderGatewayFilterFactory AbstractNameValueGatewayFilterFactory
AddRequestParameters Adds parameters to the matching request AddRequestHeaderGatewayFilterFactory AbstractNameValueGatewayFilterFactory
AddResponseHeader Adds a header to the response from the gateway AddResponseHeaderGatewayFilterFactory AbstractNameValueGatewayFilterFactory
StripPrefix Removes a prefix from the request path StripPrefixGatewayFilterFactory AbstractGatewayFilterFactory

Add Response Header Example

Adds a custom response header X-Response-Default-MyName: itheima to all routes.

spring:
  cloud:
    gateway:
      default-filters:
        - AddResponseHeader=X-Response-Default-MyName,itheima

Strip Prefix Example

StripPrefix=1 removes the first path segment (/api) from the request URI.

gateway:
  routes:
    - id: hailtaxi-driver
      uri: lb://hailtaxi-driver
      predicates:
        - Path=/api/driver/**
      filters:
        - StripPrefix=1

Behavior:

Configuration Request URL Forwarded URL
StripPrefix=1 http://localhost:8001/api/driver/info/2 http://localhost:18081/driver/info/2
StripPrefix=2 http://localhost:8001/api/suri/driver/info/2 http://localhost:18081/driver/info/2

Add Prefix Example

Uses the PrefixPath filter to add a prefix before forwarding.

gateway:
  routes:
    - id: hailtaxi-driver
      uri: lb://hailtaxi-driver
      predicates:
        - Path=/**
      filters:
        - PrefixPath=/driver
Configuration Request URL Forwarded URL
PrefixPath=/driver http://localhost:8001/info/2 http://localhost:18081/driver/info/2

Custom Filters

1. Implementing the GatewayFilter Interface

This creates a local filter that applies only to specific routes. The filter must implement GatewayFilter and Ordered.

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

public class CustomPayFilter implements GatewayFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("CustomPayFilter PRE filter executed");
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            System.out.println("CustomPayFilter POST filter executed");
        }));
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

Usage in RouteLocator: (Comment out any route configuration in application.yml)

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("hailtaxi-driver", r -> r.path("/api/driver/**")
                .and().cookie("username", "itheima")
                .and().header("token", "123456")
                .filters(f -> f.filter(new CustomPayFilter())
                        .addResponseHeader("X-Response-Default-MyName", "itheima")
                        .addRequestHeader("myheader", "1234567")
                        .stripPrefix(1))
                .uri("lb://hailtaxi-driver"))
        .route("hailtaxi-order", r -> r.path("/order/**").uri("lb://hailtaxi-order"))
        .route("hailtaxi-pay", r -> r.path("/pay/**").uri("lb://hailtaxi-pay"))
        .build();
}

2. Extending GatewayFilterFactory

This approach allows you to create a configurable filter that can be used in both code and YAML configurations.

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class PayMethodGatewayFilterFactory extends AbstractGatewayFilterFactory<PayMethodGatewayFilterFactory.Config> {

    public PayMethodGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            String payMethod = config.getPayMethod();
            String message = config.getMessage();
            log.info("PayMethodGatewayFilterFactory configuration: {} - {}", payMethod, message);
            exchange.getRequest().mutate().header("paymethod", payMethod);
            return chain.filter(exchange);
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("payMethod", "message");
    }

    @Override
    public ShortcutType shortcutType() {
        return ShortcutType.DEFAULT;
    }

    @Data
    public static class Config {
        private String payMethod;
        private String message;
    }
}

YAML configuration:

gateway:
  routes:
    - id: hailtaxi-driver
      uri: lb://hailtaxi-driver
      predicates:
        - Path=/driver/**
        - Cookie=username,itheima
        - Header=token,^(?!\d+$)[\da-zA-Z]+$
        - Method=GET,POST
      filters:
        - PayMethod=alipay,business integration

Cross-Origin (CORS) Configurasion

Global CORS Configuration

gateway:
  globalcors:
    corsConfigurations:
      '[/**]':
        allowedOrigins: "*"
        allowedMethods:
          - GET
          - POST
          - PUT

Programmatic CORS Configuration

Create a CorsWebFilter bean:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;

@Configuration
public class CorsConfig {

    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addExposedHeader("Authorization");
        config.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(source);
    }
}

Token Bucket Algorithm (Leaky Bucket / Rate Limiting)

Leaky Bucket Diagram

Flow:

  1. Every request must obtain an available token before being processed.
  2. Tokens are added to the bucket at a fixed rate, based on the configured limit.
  3. The bucket has a maximum capacity. If the bucket is full, new tokens are discarded or refused.
  4. A request must acquire a token from the bucket before proceeding with business logic. After processing, the token is removed.
  5. The bucket has a minimum threshold. When the token count reaches this minimum, tokens are not removed after processing, ensuring a minimum rate is always available.

Tags: Spring Cloud Gateway microservices API Gateway Filters Routing

Posted on Wed, 05 Aug 2026 17:08:21 +0000 by transfield