Spring Cloud Gateway: Concepts, Configuration, Routing, Filters, and CORS Handling
This article introduces Spring Cloud Gateway as a unified entry for microservices, explains its core functions, advantages over Zuul, Maven dependencies, YAML routing configuration, detailed route components, filter types with code examples, custom global filters, execution order, and CORS solutions for backend development.
1. Basic Concepts of Gateway
Spring Cloud Gateway is the unified entry point for all microservices, providing reverse proxy (request forwarding), routing & load balancing, authentication & authorization, and request rate limiting.
1.1 Main Functions
Reverse proxy (request forwarding)
Routing and load balancing
Authentication and permission control
Request rate limiting
1.2 Advantages over Zuul
Spring Cloud Gateway is built on Spring 5 WebFlux, using reactive programming for superior performance, whereas Zuul relies on the older servlet‑based, blocking model.
Although Nginx can also act as a gateway, it requires Lua scripts and has a higher learning curve; performance‑wise Nginx is the fastest, but it is rarely used as a gateway.
1.3 Architecture Diagram
Only requests coming from the gateway are accepted by microservices; direct access is denied, which greatly protects services and enables request throttling under high load.
2. Configuring Gateway in Spring Boot
2.1 Maven Dependency
<!-- Gateway starter dependency -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Nacos service discovery starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>2.2 application.yml Configuration
server:
port: 10086 # gateway port
spring:
application:
name: gateway # service name
cloud:
nacos:
server-addr: localhost:8848 # Nacos address
gateway:
routes:
- id: user-service # unique route id
uri: lb://userservice # load‑balanced target
predicates:
- Path=/user/** # match paths starting with /user/
- id: card-service
uri: lb://cardservice
predicates:
- Path=/card/**Note: Using lb://serviceName allows the address to change without modifying the YAML file, as the load balancer resolves the service name at runtime.
3. Detailed Route Configuration
Each route consists of four parts:
Route ID (id)
Target URI (uri)
Predicates – rules that determine whether a request matches the route
Filters – processing applied to the request/response
3.1 Route ID
The unique identifier for the route.
3.2 Route Target
The destination address; lb://serviceName uses load balancing, while a fixed http://... address is static and less maintainable.
3.3 Predicates
Predicates are strings parsed by Spring Cloud Gateway’s predicate factories. For example, Path=/user/** is handled by
org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory. The Path factory is the most commonly used.
3.4 Filters
Filters manipulate requests or responses. Spring Cloud Gateway provides 34 built‑in filter factories.
3.4.1 Example of a Local Request Header Filter
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
filters:
- AddRequestHeader=token,test # add request headerThis adds a header token: test to all requests routed to userservice.
3.4.2 Example of a Global Filter
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
default-filters:
- AddRequestHeader=token,test # applies to all routesFilters defined under default-filters affect every route.
4. Custom Global Filter (Java)
@Component
public class GateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. Get request parameters
MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
String userName = params.getFirst("userName");
// 2. Allow "root" user
if ("root".equals(userName)) {
return chain.filter(exchange);
}
// 3. Block others
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
return exchange.getResponse().setComplete();
}
@Override
public int getOrder() {
return -1; // higher priority (smaller value)
}
}The order value determines execution precedence; larger numbers mean lower priority.
5. Filter Execution Order
Three kinds of filters exist:
Default filters (default-filters)
Local filters defined per route (filters)
Global Java filters (implementing GlobalFilter)
The execution sequence is: default filters → route‑specific filters → global Java filters.
6. CORS Issues and Solutions
6.1 What Is CORS?
CORS (Cross‑Origin Resource Sharing) allows browsers to make AJAX requests to a different origin (different domain, port, or protocol).
6.2 Common Solutions
Configure CORS in application.yml:
spring:
cloud:
gateway:
globalcors:
add-to-simple-url-handler-mapping: true
corsConfigurations:
'[/**]':
allowedOrigins:
- "http://localhost:8090"
allowedMethods:
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*"
allowCredentials: true
maxAge: 3600006.3 Programmatic CORS Configuration
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Configuration
public class CorsConfig {
private static final String MAX_AGE = "18000L";
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
var request = ctx.getRequest();
if (!CorsUtils.isCorsRequest(request)) {
return chain.filter(ctx);
}
var requestHeaders = request.getHeaders();
var response = ctx.getResponse();
var headers = response.getHeaders();
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());
var method = requestHeaders.getAccessControlRequestMethod();
if (method != null) {
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, method.name());
}
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
return chain.filter(ctx);
};
}
}This filter adds the necessary CORS response headers and short‑circuits OPTIONS pre‑flight requests.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
