
Recently, I was working on the refactoring of the old system, and I needed to introduce a gateway service into the new system after the refactoring was completed, as an adaptation and proxy for the interface between the new system and the old system. Previously, many gateway applications used the Spring-Cloud-Netfilx solution based on the Zuul1.x version, but given that Zuul1.x had stopped iterating, it used a more traditional blocking (B)IO + multi-threaded implementation, which actually did not perform well. Then the Spring team simply redeveloped a set of gateway components on their own, and this is the Spring-Cloud-Gateway to be investigated.
Introduction
Spring Cloud Gateway relies on Spring Boot 2.0, Spring WebFlux, and Project Reactor. Many familiar synchronous libraries (such as Spring-Data and Spring-Security) and synchronous programming patterns are not available in Spring Cloud Gateway, so it is best to read the documentation for the three frameworks mentioned above first.
Spring Cloud Gateway relies on the Netty based runtime environment provided by Spring Boot and Spring WebFlux, it is not built as a WAR package or run in a traditional Servlet container.
Terminology
- Route: A route is the basic component of a gateway. It is defined by an ID, a target URI, a collection of predicates (Predicate) and a collection of filters. If the predicate aggregation is judged to be true, the route is matched.
- Predicate: uses java.util.Predicate introduced in Java8 based on functional programming. when using the predicate (aggregation) judgment, the input parameters are of type ServerWebExchange, which allows the developer to match any parameter from an HTTP request, such as HTTP request headers, HTTP request parameters, etc.
- Filter: The GatewayFilter instance created by the specified GatewayFilter factory is used to modify the request (parameters) or response (parameters) before or after sending the request downstream.
Actually, Filter also includes GlobalFilter, but it is not mentioned in the official documentation.
Working Principle

The client sends a request to Spring Cloud Gateway and if the Gateway Handler Mapping module processes the current request if it matches a target route configuration, the request is forwarded to the Gateway Web Handler module. When the Gateway Web Handler module sends the request, it passes the request through a chain of filters that match the request. The reason the filters are separated by dashed lines in the above diagram is that the filter processing logic can be executed before or after the proxy request is sent. All pre type filters are executed before the proxy request is created (and sent), and all post type filters are executed when the proxy request is created (and sent).
See the above figure, if the external request comes in and falls into the filter chain, then the left side of the dotted line is the pre type filter, and the request goes through the pre type filter first, and then is sent to the target proxied service. The target proxied service responds to the request, and the response goes through the filter chain again, that is, through the filter chain on the right side of the dotted line, and these filters are the post filters.
Note that if the corresponding routing port is not explicitly specified in the routing configuration, the following default port will be used.
- HTTP protocol, use port 80.
- HTTPS protocol, use port 443.
Introduction of dependencies
It is recommended to introduce Spring-Cloud-Gateway directly through the Train version (in fact, I have checked that the code name of the Train version is actually the naming of the London Underground station, like the current Spring Cloud latest version is Greenwich.SR1, Greenwich can be found in the map of London Underground station, corresponding to the SpringBoot version is 2.1.x) into Spring-Cloud-Gateway, as this will keep up with the latest stable version of Spring-Cloud, and because Spring-Cloud-Gateway is based on the Netty runtime environment to start, there is no need to introduce the Servlet container with the spring-boot-starter-web with a Servlet container.
The parent POM introduces the following configuration.
|  |  | 
submodule or the module POM that needs to introduce Spring-Cloud-Gateway introduces the following configuration.
Creating a starter class is sufficient.
Gateway Configuration
The gateway configuration eventually needs to be translated into a collection of RouteDefinition, with the following interface for the definition of the configuration.
Configuration through YAML files or streaming programmatic configuration (in fact, there is also DiscoveryClient for configuration with Eureka in the documentation, which will not be studied here for now) is ultimately aimed at creating a collection of RouteDefinition.
Yaml configuration
The configuration implementation is PropertiesRouteDefinitionLocator, associated with the configuration class GatewayProperties.
|  |  | 
Programmatic streaming configuration
Programmatic and streaming configurations rely on the RouteLocatorBuilder and the goal is to construct a RouteLocator instance.
Routing Predicate Factory
Spring Cloud Gateway uses Route as part of the HandlerMapping component infrastructure of Spring-WebFlux, which means that when HandlerMapping does the matching, it includes the configured routing rules in the matching mechanism. Spring Cloud Gateway itself contains a number of built-in routing predicate factories. Each of these predicates matches a different attribute of an HTTP request. Multiple routing predicate factories can be combined together using and logic.
The built-in routing predicate factories currently provided by Spring Cloud Gateway are as follows.

Specify date-time rule routing predicates
There are three optional rules for the routing predicate specified by the configured datetime.
- Match requests before the specified datetime.
- The match request is after the specified date time.
- The matching request is between the specified datetime.
It is important to note that the configured datetime must satisfy the ZonedDateTime format.
For example, if the gateway application is live on 2019-05-01T00:00:00+08:00 [Asia/Shanghai], and all requests after the live date are routed to www.throwable.club, then the configuration is as follows.
In this case, as long as the request gateway http://localhost:9090, the request will be forwarded to http://www.throwable.club.
If you want to allow only requests before 2019-05-01T00:00:00+08:00[Asia/Shanghai], then just change it to.
If only the time between two date periods is allowed to be requested, then simply read
Then only requests from May 1, 2019, 0:00 to May 2, 2019, 0:00 will be routed properly.
Cookie routing predicates
The CookieRoutePredicateFactory takes two parameters, the name of the Cookie and a regular expression (value). Only if the name and value corresponding to the Cookie in the request match the values configured in the Cookie route predicate will a hit be matched for routing.
The request needs to carry a cookie, the name is doge and the value needs to match the regular expression throwable to route to http://www.throwable.club.
Here we try to build an order Order service locally, based on SpringBoot 2.1.4, started on port 9091.
|  |  | 
The application.yaml configuration for the order service.
Gateway routing configuration.
Header routing predicate
The HeaderRoutePredicateFactory takes two parameters, the name of the Header and a regular expression (value). Only if the name and value corresponding to the Header in the request match the values configured in the Header route predicate, a hit will be matched for routing.
A new /header endpoint is added to the order service.
|  |  | 
The routing configuration of the gateway is as follows.
Host routing predicates
The HostRoutePredicateFactory only needs to specify a list of host names, and each element in the list supports the Ant naming style, using . is used as a separator and multiple elements are distinguished from each other using ,. The Host routing predicate actually targets the Host attribute in the HTTP request header.
A new /header endpoint is added to the order service.
|  |  | 
The routing configuration of the gateway is as follows.
In fact, it is possible to customize more diverse Host matching patterns and even support URI template variables.
Request method routing predicates
The MethodRoutePredicateFactory takes only one parameter: the HTTP request method to be matched.
The routing configuration of the gateway is as follows.
Configured this way, all incoming requests to the GET method of the gateway will be routed to http://localhost:9091.
A new /get endpoint is added to the order service.
Request path routing predicates
The PathRoutePredicateFactory takes a list of PathMatcher pattern paths and an optional flag bit parameter matchOptionalTrailingSeparator. This is one of the most commonly used routing predicates.
In addition, paths can be configured with {segment} placeholders such as /foo/1 or /foo/bar or /bar/baz, if configured in this form, when matching hits for routing, the corresponding content in the path will be extracted and the key-value pairs will be placed in the ServerWebExchange. getAttributes() collection, KEY is ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE, these extracted attributes can be used by GatewayFilter Factories.
Request query parameter routing predicate
The QueryRoutePredicateFactory takes a mandatory request query parameter (name of param) and an optional regular expression (regexp).
The param configured here is doge and the regular expression is throwabl..
Remote IP address routing predicate
The RemoteAddrRoutePredicateFactory match rule takes a list of CIDR symbolic (IPv4 or IPv6) strings (minimum value is 1), e.g. 192.168.0.1/16 (where 192.168.0.1 is the remote IP address and 16 is the subnet mask).
There are actually many extensions to the routing predicate of remote IP routing, so I won’t start here for now.
Multiple routing predicate combinations
Because the predicates attribute in the routing configuration is actually a list, multiple routing rules can be added directly.
These rules are logically combined using and, e.g. the example above is equivalent to
GatewayFilter Factory
A routing filter GatewayFilter allows modifying the content of an incoming HTTP request or the content of a returned HTTP response. The scope of a routing filter is a specific routing configuration. Spring Cloud Gateway provides a rich set of built-in GatewayFilter factories that can be selected on demand.
Because there are so many GatewayFilter factory classes, I’ll give a simple example here.
If we want to attach special HTTP request headers to some requests, we can use AddRequestHeaderX-Request-Foo:Bar, application.yml as follows.
Then all HTTP requests from the gateway portal will have a special HTTP request header added: X-Request-Foo:Bar.
The current built-in implementation of the GatewayFilter factory is as follows.
| ID | class | type | Function | 
|---|---|---|---|
| StripPrefix | StripPrefixGatewayFilterFactory | pre | Remove the first part of the request URLpath, e.g. the original request path is/order/query, after processing it is/query | 
| SetStatus | SetStatusGatewayFilterFactory | post | Setting the HTTP status code (parsed from org.springframework.http.HttpStatus) | 
| SetResponseHeader | SetResponseHeaderGatewayFilterFactory | post | Set (add) the response header of the request response | 
| SetRequestHeader | SetRequestHeaderGatewayFilterFactory | pre | Set (add) request header | 
| SetPath | SetPathGatewayFilterFactory | pre | Set (override) request path | 
| SecureHeader | SecureHeadersGatewayFilterFactory | pre | Set security-related request headers, see SecureHeadersProperties | 
| SaveSession | SaveSessionGatewayFilterFactory | pre | Save WebSession | 
| RewriteResponseHeader | RewriteResponseHeaderGatewayFilterFactory | post | Re-response header | 
| RewritePath | RewritePathGatewayFilterFactory | pre | Rewrite the request path | 
| Retry | RetryGatewayFilterFactory | pre | Retry requests based on conditions | 
| RequestSize | RequestSizeGatewayFilterFactory | pre | Limit the size of the request in byte, exceeding the set value returns 413 Payload Too Large | 
| RequestRateLimiter | RequestRateLimiterGatewayFilterFactory | pre | Restricted flow | 
| RequestHeaderToRequestUri | RequestHeaderToRequestUriGatewayFilterFactory | pre | Change the request URL by the value of the request header | 
| RemoveResponseHeader | RemoveResponseHeaderGatewayFilterFactory | post | Remove the configured response header | 
| RemoveRequestHeader | RemoveRequestHeaderGatewayFilterFactory | pre | Remove the configured request header | 
| RedirectTo | RedirectToGatewayFilterFactory | pre | Redirect, need to specify HTTP status code and redirect URL | 
| PreserveHostHeader | PreserveHostHeaderGatewayFilterFactory | pre | Set the attribute preserveHostHeadercarried by the request totrue | 
| PrefixPath | PrefixPathGatewayFilterFactory | pre | Request path add predecessor path | 
| Hystrix | HystrixGatewayFilterFactory | pre | Integrating Hystrix | 
| FallbackHeaders | FallbackHeadersGatewayFilterFactory | pre | The Hystriximplementation allows for exception details to be carried through the request header if the hit downgrade logic | 
| AddResponseHeader | AddResponseHeaderGatewayFilterFactory | post | Add response headers | 
| AddRequestParameter | AddRequestParameterGatewayFilterFactory | pre | Add request parameters, limited to the Queryparameter of theURLonly | 
| AddRequestHeader | AddRequestHeaderGatewayFilterFactory | pre | Add request header | 
When using the GatewayFilter factory, you need to know its ID and how to configure it, which can be seen in the public static internal class XXXXConfig of the corresponding factory class.
GlobalFilter Factory
The function of GlobalFilter is actually the same as GatewayFilter, except that the scope of GlobalFilter is all route configurations, not bound to the specified route configuration. Multiple GlobalFilters can specify the order of execution of each GlobalFilter via the @Order or getOrder() methods. The smaller the order value, the higher the priority of GlobalFilter execution.
Note that since there are two types of filters, pre and post, the pre type filter should be at the top of the pre filter chain if the order value is smaller, and the post type filter should be at the bottom of the pre filter chain if the order value is smaller. The schematic diagram is as follows.

For example, to implement the load balancing feature, application.yml is configured as follows.
The built-in GlobalFilter currently provided by Spring Cloud Gateway is as follows.
| class | Function | 
|---|---|
| ForwardRoutingFilter | Redirection | 
| LoadBalancerClientFilter | Load Balancing | 
| NettyRoutingFilter | Netty’s HTTP client routing | 
| NettyWriteResponseFilter | Netty response for write operations | 
| RouteToRequestUrlFilter | Update URL based on routing configuration | 
| WebsocketRoutingFilter | Websocket request forwarding to downstream | 
Most of the built-in GlobalFilters are related to the properties of ServerWebExchangeUtils, so we won’t go into depth here.
Cross configuration
The gateway can control the global CORS behavior through configuration. The global CORS configuration corresponds to the class CorsConfiguration, which is a mapping of the URL schema. For example, the application.yaml file is as follows.
In the above example, for all requested paths, CORS requests will be allowed from docs.spring.io and are GET methods.
Actuator Endpoint Related
To introduce spring-boot-starter-actuator, you need to do the following configuration to enable the gateway monitoring endpoint.
Current list of supported endpoints.
| ID | request path | HTTP method | Description | 
|---|---|---|---|
| globalfilters | /actuator/gateway/globalfilters | GET | Show the list of GlobalFilter in the routing configuration | 
| routefilters | /actuator/gateway/routefilters | GET | Show the list of GatewayFilters bound to the corresponding route configuration | 
| refresh | /actuator/gateway/refresh | POST | Emptying the routing configuration cache | 
| routes | /actuator/gateway/routes | GET | Display a list of defined routing configurations | 
| routes/{id} | /actuator/gateway/routes/{id} | GET | Display the routing configuration already defined for the corresponding ID | 
| routes/{id} | /actuator/gateway/routes/{id} | POST | Add a new routing configuration | 
| routes/{id} | /actuator/gateway/routes/{id} | DELETE | Delete the routing configuration for the specified ID | 
where /actuator/gateway/routes/{id} adds a new route configuration request parameter in the following format.
Summary
Although the author is a developer at the bottom, but a long time ago said to friends around.
Reactive programming combined with synchronous non-blocking IO or asynchronous non-blocking IO is the mainstream direction of the current network programming framework, it is best to keep pace with the mainstream to master the use of these frameworks, the best ability to become their contributors
The common reactive programming frameworks currently available are.
- Reactor and RxJava2, whereReactoris more common in back-end JVM applications, andRxJava2is more common in APP clients written for Android.
- Reactor-Netty, this is based on Reactor and Netty package .
- Spring-WebFluxand- Spring-Cloud-Gateway, where- Spring-Cloud-Gatewaydepends on- Spring-WebFluxand- Spring-WebFluxunderlying depends on- Reactor-Netty.
According to this chain, it is better to learn Reactor and Netty systematically.
Reference.
Appendix
The Spring-Cloud-Gateway was chosen not only to use the new technology, but more importantly for its impressive performance improvements. The results of the benchmarking project spring-cloud-gateway-bench are as follows.
| Proxy | Avg Latency | Avg Requests/Sec | 
|---|---|---|
| Spring Cloud Gateway | 6.61ms | 32213.38 | 
| Linkered | 7.62ms | 28050.76 | 
| Zuul(1.x) | 12.56ms | 20800.13 | 
| None(Direct call) | 2.09ms | 116841.15 | 
Reference https://www.throwx.cn/2019/05/03/spring-cloud-gateway-guide/