Spring Cloud Gateway provides API gateway support for SpringBoot applications and has powerful intelligent routing and filter functions. This article will introduce its usage in detail.
Introduction to Gateway
Gateway is an API gateway service built on the Spring ecosystem and is based on technologies such as Spring 5, Spring Boot 2 and Project Reactor. Gateway aims to provide a simple and effective way to route APIs and provide some powerful filter functions, such as fusing, current limiting, Retry, etc.
Spring Cloud Gateway has the following features:
- Based on Spring Framework 5, Project Reactor and Spring Boot 2.0;
- Dynamic routing: it can match any request attribute;
- You can specify Predicate and Filter for the route;
- Integrated circuit breaker function of Hystrix;
- Integrate Spring Cloud service discovery function;
- Easy to write Predicate and Filter;
- Request current limiting function;
- Path rewriting is supported.
Related concepts
- Route: route is the basic module for building gateway. It consists of ID, target URI, a series of assertions and filters. If the assertion is true, the route will be matched;
- Predicate: refers to the Function Predicate of Java 8. The input type is ServerWebExchange in the Spring framework. This allows developers to match everything in the HTTP request, such as the request header or request parameters. Route if the request matches the assertion;
- Filter: refers to the instance of GatewayFilter in the Spring framework. Using the filter, you can modify the request before and after it is routed.
Create project module
Here we create an API Gateway module to demonstrate the common functions of Gateway.
Introduce dependency
In POM Add related dependencies to XML:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
Related configuration
Gateway provides two different ways to configure routing, one is through yml file, the other is through Java Bean. Let's introduce them respectively.
Method 1: use yml configuration
In application Configure in YML:
server: port: 9201 service-url: user-service: http://localhost:8201 spring: cloud: gateway: routes: - id: path_route #ID of the route uri: ${service-url.user-service}/user/{id} #Route address after matching predicates: # Assert that the path matches the route - Path=/user/{id}
Start Eureka server, user service and API gateway services, and call the address to test: http://localhost:9201/user/1 , we found that the request was routed to the path of user service: http://localhost:8201/user/1
Method 2: use Java Bean configuration
Add relevant configuration classes and configure a RouteLocator object:
@Configuration public class GatewayConfig { @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route("path_route2", r -> r.path("/user/getByUsername") .uri("http://localhost:8201/user/getByUsername")) .build(); } }
Restart the API gateway service and call the address test: http://localhost:9201/user/getByUsername?username=antonio , we found that the request was routed to the path of user service: http://localhost:8201/user/getByUsername?username=antonio
Use of Route Predicate
Spring gateway is used as part of the spring gateway routing infrastructure. Spring Cloud Gateway includes many built-in route predict factories. All these predictions match the different attributes of the HTTP request. Multiple route predictors can be combined. Let's introduce some common route predictors.
Note: the configurations mentioned in predict are all in application predict YML file and start the API gateway service with this configuration.
After Route Predicate
Requests after the specified time will match the route.
spring: cloud: gateway: routes: - id: after_route uri: ${service-url.user-service} predicates: - After=2019-09-24T16:30:00+08:00[Asia/Shanghai]
Before Route Predicate
Requests before the specified time will match the route.
spring: cloud: gateway: routes: - id: before_route uri: ${service-url.user-service} predicates: - Before=2019-09-24T16:30:00+08:00[Asia/Shanghai]
Between Route Predicate
Requests within the specified time interval will match the route.
spring: cloud: gateway: routes: - id: before_route uri: ${service-url.user-service} predicates: - Between=2019-09-24T16:30:00+08:00[Asia/Shanghai], 2019-09-25T16:30:00+08:00[Asia/Shanghai]
Cookie Route Predicate
Requests with the specified Cookie match the route.
spring: cloud: gateway: routes: - id: cookie_route uri: ${service-url.user-service} predicates: - Cookie=username,antonio
Using curl tool to send a request with Cookie username=antonio can match the route.
$ curl http://localhost:9201/user/1 --cookie "username=antonio"
Header Route Predicate
The request with the specified request header matches the route.
spring: cloud: gateway: routes: - id: header_route uri: ${service-url.user-service} predicates: - Header=X-Request-Id, \d+
Using curl tool to send a request with request header X-Request-Id:123 can match the route.
$ curl http://localhost:9201/user/1 -H "X-Request-Id:123"
Host Route Predicate
Requests with the specified Host will match the route.
spring: cloud: gateway: routes: - id: host_route uri: ${service-url.user-service} predicates: - Host=**.antoniopeng.com
Use curl tool to send a request with a header of host: www.antonionopeng Com requests can match the route.
$ curl http://localhost:9201/user/1 -H "Host:www.antoniopeng.com"
Method Route Predicate
The request to send the specified method will match the route.
spring: cloud: gateway: routes: - id: method_route uri: ${service-url.user-service} predicates: - Method=GET
The route can be matched by sending a GET request using the curl tool.
$ curl http://localhost:9201/user/1
Sending a POST request using curl tool cannot match the route.
$ curl -X POST http://localhost:9201/user/1
Path Route Predicate
The request to send the specified path will match the route.
spring: cloud: gateway: routes: - id: path_route uri: ${service-url.user-service}/user/{id} predicates: - Path=/user/{id}
Using curl tool to send / user/1 path request can match this route.
$ curl http://localhost:9201/user/1
The / abc/1 path request sent by curl tool cannot match the route.
$ curl http://localhost:9201/abc/1
Query Route Predicate
Requests with specified query parameters can match the route.
spring: cloud: gateway: routes: - id: query_route uri: ${service-url.user-service}/user/getByUsername predicates: - Query=username
Using curl tool to send a request with username=antonio query parameter can match the route.
$ curl http://localhost:9201/user/getByUsername?username=antonio
Sending a request with or without query parameters using curl tool cannot match the route.
$ curl http://localhost:9201/user/getByUsername
RemoteAddr Route Predicate
Requests originating from the specified remote address can match the route.
spring: cloud: gateway: routes: - id: remoteaddr_route uri: ${service-url.user-service} predicates: - RemoteAddr=192.168.1.1/24
The route can be matched by sending a request from 192.168.1.1 using curl tool.
$ curl http://localhost:9201/user/1
Weight Route Predicate
Use the weight to route the corresponding requests. The following shows that 80% of the requests will be routed to localhost:8201 and 20% to localhost:8202.
spring: cloud: gateway: routes: - id: weight_high uri: http://localhost:8201 predicates: - Weight=group1, 8 - id: weight_low uri: http://localhost:8202 predicates: - Weight=group1, 2
Use of Route Filter
The routing filter can be used to modify the incoming HTTP request and the returned HTTP response. The routing filter can only be used by specifying the route. Spring Cloud Gateway has built-in multiple routing filters, which are generated by the factory class of GatewayFilter. Let's introduce the usage of common routing filters.
AddRequestParameter GatewayFilter
A filter that adds parameters to the request.
spring: cloud: gateway: routes: - id: add_request_parameter_route uri: http://localhost:8201 filters: - AddRequestParameter=username, antonio predicates: - Method=GET
The above configuration will add the request parameter of username=antonio to the GET request, and use the following command to test through curl tool.
$ curl http://localhost:9201/user/getByUsername
Equivalent to initiating the request:
$ curl http://localhost:8201/user/getByUsername?username=antonio
StripPrefix GatewayFilter
A filter that removes a specified number of path prefixes.
spring: cloud: gateway: routes: - id: strip_prefix_route uri: http://localhost:8201 predicates: - Path=/user-service/** filters: - StripPrefix=2
The above configuration will remove two bits from the path of the request starting with / user service /, and use the following command to test through curl tool.
$ curl http://localhost:9201/user-service/a/user/1
Equivalent to initiating the request:
$ curl http://localhost:8201/user/1
PrefixPath GatewayFilter
Contrary to the StripPrefix filter, it is a filter that adds to the original path.
spring: cloud: gateway: routes: - id: prefix_path_route uri: http://localhost:8201 predicates: - Method=GET filters: - PrefixPath=/user
The above configuration will add / user path prefix to all GET requests, and use the following command to test through curl tool.
$ curl http://localhost:9201/1
Equivalent to initiating the request:
$ curl http://localhost:8201/user/1
Hystrix GatewayFilter
The Hystrix filter allows you to add the circuit breaker function to the gateway routing, protect your service from cascading failures, and provide service degradation processing.
To turn on the circuit breaker function, we need to switch on the POM Add the related dependencies of Hystrix in XML:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
Then add the processing class of related service degradation:
@RestController public class FallbackController { @GetMapping("/fallback") public Object fallback() { Map<String,Object> result = new HashMap<>(); result.put("data",null); result.put("message","Get request fallback!"); result.put("code",500); return result; } }
In application filter Add relevant configurations in YML. When the route fails, it will be forwarded to the controller for service degradation processing:
spring: cloud: gateway: routes: - id: hystrix_route uri: http://localhost:8201 predicates: - Method=GET filters: - name: Hystrix args: name: fallbackcmd fallbackUri: forward:/fallback
Close the user service and call the address to test: http://localhost:9201/user/1 , it is found that the processing information of service degradation has been returned.
RequestRateLimiter GatewayFilter
The RequestRateLimiter filter can be used to limit the flow. The RateLimiter implementation is used to determine whether to allow the current request to continue. If the request is too large, the HTTP 429- too many request status will be returned by default.
In POM Add related dependencies to XML:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency>
Add the configuration class of current limiting policy. There are two strategies: one is to limit the flow according to the username in the request parameter, and the other is to limit the flow according to the access IP:
@Configuration public class RedisRateLimiterConfig { @Bean KeyResolver userKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username")); } @Bean public KeyResolver ipKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); } }
We use Redis to limit the flow, so we need to add the configuration of Redis and RequestRateLimiter. All GET requests are limited by IP:
server: port: 9201 spring: redis: host: localhost password: 123456 port: 6379 cloud: gateway: routes: - id: requestratelimiter_route uri: http://localhost:8201 filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 1 #Number of requests allowed to be processed per second redis-rate-limiter.burstCapacity: 2 #Maximum number of requests processed per second key-resolver: "#{@ipKeyResolver}" #Current limiting policy, Bean corresponding to the policy predicates: - Method=GET logging: level: org.springframework.cloud.gateway: debug
Multiple requests for this address: http://localhost:9201/user/1 , an error with status code 429 will be returned:
Retry GatewayFilter
The filter that retries the routing request can determine whether to retry according to the HTTP status code returned by the routing request.
Modify application Yaml profile:
spring: cloud: gateway: routes: - id: retry_route uri: http://localhost:8201 predicates: - Method=GET filters: - name: Retry args: retries: 1 #Number of retries required statuses: BAD_GATEWAY #Which status code needs to be returned for retry? The status code returned is 5XX for retry backoff: firstBackoff: 10ms maxBackoff: 50ms factor: 2 basedOnPreviousValue: false
When the call returns 500, it will retry and access the test address: http://localhost:9201/user/111 , it can be found that the user service console reported an error twice, indicating a retry.
2019-10-27 14:08:53.435 ERROR 2280 --- [nio-8201-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause java.lang.NullPointerException: null at com.antonio.cloud.controller.UserController.getUser(UserController.java:34) ~[classes/:na]
Use with registry
Last time we talked about using Zuul as a gateway in combination with the registry. By default, Zuul will create a dynamic route with the service name as the path according to the service list registered in the registry. Gateway also realizes this function. Let's demonstrate how the gateway uses the default dynamic routing and filter in combination with the registry.
Use dynamic routing
In POM Add related dependencies to XML:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
Add application Eureka YML profile:
server: port: 9201 spring: application: name: api-gateway cloud: gateway: discovery: locator: enabled: true #Enable the function of dynamically creating routes from the registry lower-case-service-id: true #Use lowercase service name, which is uppercase by default eureka: client: service-url: defaultZone: http://localhost:8001/eureka/ logging: level: org.springframework.cloud.gateway: debug
Use application Eureka YML configuration file starts API gateway service and accesses http://localhost:9201/user-service/user/1 , which can be routed to the user service http://localhost:8201/user/1 Office.
Use filter
When using the filter in combination with the registry, we should note that the protocol of uri is lb, so as to enable the load balancing function of Gateway.
Modify application Eureka YML file, using PrefixPath filter, will add / user path for all GET request paths and route:
server: port: 9201 spring: application: name: api-gateway cloud: gateway: routes: - id: prefixpath_route uri: lb://User service # requires lb protocol predicates: - Method=GET filters: - PrefixPath=/user discovery: locator: enabled: true eureka: client: service-url: defaultZone: http://localhost:8001/eureka/ logging: level: org.springframework.cloud.gateway: debug
Use application Eureka YML configuration file starts API gateway service and accesses http://localhost:9201/1 , which can be routed to the user service http://localhost:8201/user/1 Office.
For more dry goods, please move to: https://antoniopeng.com