Gateway acts as the unified entry point for all microservices. It handles the following:
- Authentication and Authorization: As the microservice entry, the gateway verifies if a user is authorized to make a request. If not, it blocks the request.
- Request Routing, Load Balancing: All requests must pass through the gateway first. The gateway doesn’t handle business logic directly. Instead, it forwards requests to a specific microservice based on defined rules – that’s routing. If multiple target services are available for a route, load balancing is also applied.
- Request Rate Limiting: When traffic is too high, the gateway throttles requests to match the downstream microservice’s capacity, preventing services from getting overloaded.
Spring Cloud offers two gateway implementations:
- Zuul: Built on Servlet, uses blocking I/O.
- SpringCloudGateway: Based on Spring5’s WebFlux, it’s a reactive programming implementation with better performance.
Getting Started
Create a project and add the dependencies:
| |
Write the basic configuration and routing rules:
| |
Then, visit localhost:10010/user/1 to test it.
Routing configuration includes:
- Route ID: The unique identifier for the route.
- Route Target (URI): The target address for the route. ‘http’ means a fixed address, ’lb’ means load balancing based on service name.
- Route Predicates: Rules that determine if a request matches the route. If it matches, the request is forwarded to the route’s destination.
- Route Filters: Process requests or responses.
Predicate Factories
The predicate rules defined in the configuration are just strings. These strings are read and processed by Predicate Factories, turning them into conditions for route matching.
For example, the Path=/user/** rule from above matches by path and is handled by the org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory class. Similar predicate factories include:
| Name | Description | Example |
|---|---|---|
| After | Requests after a certain time | - After=2037-01-20T17:42:47.789-07:00[America/Denver] |
| Before | Requests before a certain time | - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] |
| Between | Requests between two specific times | - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] |
| Cookie | Request must include certain cookies | - Cookie=chocolate, ch.p |
| Header | Request must include certain headers | - Header=X-Request-Id, \d+ |
| Host | Request must be for a specific host (domain) | - Host=.somehost.org,.anotherhost.org |
| Method | Request method must be specified | - Method=GET,POST |
| Path | Request path must match specified rules | - Path=/red/{segment},/blue/** |
| Query | Request parameters must include specified parameters | - Query=name, Jack or - Query=name |
| RemoteAddr | Requester’s IP must be within a specified range | - RemoteAddr=192.168.1.1/24 |
| Weight | Weight handling |
Filter Factories
A GatewayFilter is a type of filter provided in the gateway that can process requests entering the gateway and responses returned by microservices.
Spring provides 31 different route filter factories, for example:
| Name | Description |
|---|---|
| AddRequestHeader | Adds a request header to the current request |
| RemoveRequestHeader | Removes a request header from the request |
| AddResponseHeader | Adds a response header to the response |
| RemoveResponseHeader | Removes a response header from the response |
| RequestRateLimiter | Limits request traffic |
For more details, see: https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway/gatewayfilter-factories.html
Request Header Filter
Let’s take the request header filter as an example: add a request header ‘Hello=World’ to all requests going to ‘userService’.
Modify application.yml in your gateway project to add a route filter:
| |
Then, you can modify the Controller to test it:
| |
Default Filters
If you want a filter factory to apply to all routes, you can put it under ‘default-filters’.
| |
Global Filters
The gateway provides 31 types of filters, but each has a fixed purpose. If we want to intercept requests and implement our own custom business logic, these fixed filters won’t cut it.
Global Filters, on the other hand, also process all requests entering the gateway and responses from microservices, just like GatewayFilters. The difference is that GatewayFilters are configuration-driven with fixed logic, while GlobalFilter logic requires custom code by implementing the GlobalFilter interface.
| |
By writing custom logic in the filter, you can achieve the following functionalities:
- Login status check
- Permission validation
- Request rate limiting, etc.
Basic Usage
Goal: Define a global filter to intercept requests and check if the request parameters meet the following conditions:
- Does the parameter contain ‘authorization’?
- Is the ‘authorization’ parameter value ‘admin’?
If both conditions are met, proceed; otherwise, block the request.
First, define a filter in the gateway:
| |
Filter Execution Order
When a request enters the gateway, it encounters three types of filters: current route filters, Default Filters, and Global Filters.
After routing, the current route filters, Default Filters, and Global Filters are merged into a single filter chain (collection). They are then sorted and executed sequentially.
Each filter has an integer ‘order’ value. A smaller ‘order’ value means higher priority and earlier execution.
The ‘order’ values for route filters and default filters are assigned by Spring, defaulting to an incrementing sequence starting from 1.
GlobalFilters can specify their ‘order’ value by implementing the ‘Ordered’ interface or by adding the ‘@Order’ annotation. We define these values.
If filters have the same ‘order’ value, they are executed in the sequence: DefaultFilter > Route Filter > GlobalFilter.
Here’s how to specify the order value by implementing an interface:
| |
Cross-Origin (CORS) Issues
Same origin means same protocol, same IP or domain, and same port.
A cross-origin issue occurs when the browser blocks an AJAX request from the requester to a server if they are from different origins. The solution is CORS.
| |