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 URL path, 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 preserveHostHeader carried by the request to true |
PrefixPath | PrefixPathGatewayFilterFactory | pre | Request path add predecessor path |
Hystrix | HystrixGatewayFilterFactory | pre | Integrating Hystrix |
FallbackHeaders | FallbackHeadersGatewayFilterFactory | pre | The Hystrix implementation 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 Query parameter of the URL only |
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 GlobalFilter
s 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 GlobalFilter
s 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 GatewayFilter s 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
, whereReactor
is more common in back-end JVM applications, andRxJava2
is more common in APP clients written for Android. Reactor-Netty
, this is based on Reactor and Netty package .Spring-WebFlux
andSpring-Cloud-Gateway
, whereSpring-Cloud-Gateway
depends onSpring-WebFlux
andSpring-WebFlux
underlying depends onReactor-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/