GVKun编程网logo

Spring Cloud Gateway(springcloudgateway负载均衡)

13

如果您对SpringCloudGateway和springcloudgateway负载均衡感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解SpringCloudGateway的各种细节,并对sp

如果您对Spring Cloud Gatewayspringcloudgateway负载均衡感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解Spring Cloud Gateway的各种细节,并对springcloudgateway负载均衡进行深入的分析,此外还有关于Fizz Gateway基准测试性能超越Spring Cloud Gateway、Spring cloud - gateway、Spring Cloud gateway - CircuitBreaker GatewayFilte、Spring Cloud gateway 三 自定义过滤器 GatewayFilter的实用技巧。

本文目录一览:

Spring Cloud Gateway(springcloudgateway负载均衡)

Spring Cloud Gateway(springcloudgateway负载均衡)

Spring Cloud Gateway

2.2.0.M1

This project provides an API Gateway built on top of the Spring Ecosystem, including: Spring 5, Spring Boot 2 and Project Reactor. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency.

How to Include Spring Cloud Gateway

To include Spring Cloud Gateway in your project use the starter with group org.springframework.cloud and artifact id spring-cloud-starter-gateway. See the Spring Cloud Project page for details on setting up your build system with the current Spring Cloud Release Train.

If you include the starter, but, for some reason, you do not want the gateway to be enabled, set spring.cloud.gateway.enabled=false.

  Spring Cloud Gateway is built upon Spring Boot 2.0, Spring WebFlux, and Project Reactor. As a consequence many of the familiar synchronous libraries (Spring Data and Spring Security, for example) and patterns you may not apply when using Spring Cloud Gateway. If you are unfamiliar with these projects we suggest you begin by reading their documentation to familiarize yourself with some of the new concepts before working with Spring Cloud Gateway.
  Spring Cloud Gateway requires the Netty runtime provided by Spring Boot and Spring Webflux. It does not work in a traditional Servlet Container or built as a WAR.

Glossary

  • Route: Route the basic building block of the gateway. It is defined by an ID, a destination URI, a collection of predicates and a collection of filters. A route is matched if aggregate predicate is true.

  • Predicate: This is a Java 8 Function Predicate. The input type is a Spring Framework ServerWebExchange. This allows developers to match on anything from the HTTP request, such as headers or parameters.

  • Filter: These are instances Spring Framework GatewayFilter constructed in with a specific factory. Here, requests and responses can be modified before or after sending the downstream request.

How It Works

Spring Cloud Gateway Diagram

Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a Route, it is sent to the Gateway Web Handler. This handler runs sends the request through a filter chain that is specific to the request. The reason the filters are divided by the dotted line, is that filters may execute logic before the proxy request is sent or after. All "pre" filter logic is executed, then the proxy request is made. After the proxy request is made, the "post" filter logic is executed.

  URIs defined in routes without a port will get a default port set to 80 and 443 for HTTP and HTTPS URIs respectively.

Route Predicate Factories

Spring Cloud Gateway matches routes as part of the Spring WebFlux HandlerMapping infrastructure. Spring Cloud Gateway includes many built-in Route Predicate Factories. All of these predicates match on different attributes of the HTTP request. Multiple Route Predicate Factories can be combined and are combined via logical and.

After Route Predicate Factory

The After Route Predicate Factory takes one parameter, a datetime. This predicate matches requests that happen after the current datetime.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]

This route matches any request after Jan 20, 2017 17:42 Mountain Time (Denver).

Before Route Predicate Factory

The Before Route Predicate Factory takes one parameter, a datetime. This predicate matches requests that happen before the current datetime.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: https://example.org
        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]

This route matches any request before Jan 20, 2017 17:42 Mountain Time (Denver).

Between Route Predicate Factory

The Between Route Predicate Factory takes two parameters, datetime1 and datetime2. This predicate matches requests that happen after datetime1 and before datetime2. The datetime2 parameter must be after datetime1.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: https://example.org
        predicates:
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

This route matches any request after Jan 20, 2017 17:42 Mountain Time (Denver) and before Jan 21, 2017 17:42 Mountain Time (Denver). This could be useful for maintenance windows.

Cookie Route Predicate Factory

The Cookie Route Predicate Factory takes two parameters, the cookie name and a regular expression. This predicate matches cookies that have the given name and the value matches the regular expression.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://example.org
        predicates:
        - Cookie=chocolate, ch.p

This route matches the request has a cookie named chocolate who’s value matches the ch.p regular expression.

Header Route Predicate Factory

The Header Route Predicate Factory takes two parameters, the header name and a regular expression. This predicate matches with a header that has the given name and the value matches the regular expression.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - Header=X-Request-Id, \d+

This route matches if the request has a header named X-Request-Id whose value matches the \d+ regular expression (has a value of one or more digits).

Host Route Predicate Factory

The Host Route Predicate Factory takes one parameter: a list of host name patterns. The pattern is an Ant style pattern with . as the separator. This predicates matches the Host header that matches the pattern.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

URI template variables are supported as well, such as {sub}.myhost.org.

This route would match if the request has a Host header has the value www.somehost.org or beta.somehost.org or www.anotherhost.org.

This predicate extracts the URI template variables (like sub defined in the example above) as a map of names and values and places it in the ServerWebExchange.getAttributes() with a key defined in ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE. Those values are then available for use by GatewayFilter Factories

Method Route Predicate Factory

The Method Route Predicate Factory takes one parameter: the HTTP method to match.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: https://example.org
        predicates:
        - Method=GET

This route would match if the request method was a GET.

Path Route Predicate Factory

The Path Route Predicate Factory takes two parameters: a list of Spring PathMatcher patterns and an optional flag to matchOptionalTrailingSeparator.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        - Path=/foo/{segment},/bar/{segment}

This route would match if the request path was, for example: /foo/1 or /foo/bar or /bar/baz.

This predicate extracts the URI template variables (like segment defined in the example above) as a map of names and values and places it in the ServerWebExchange.getAttributes() with a key defined in ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE. Those values are then available for use by GatewayFilter Factories

A utility method is available to make access to these variables easier.

Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);

String segment = uriVariables.get("segment");

Query Route Predicate Factory

The Query Route Predicate Factory takes two parameters: a required param and an optional regexp.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=baz

This route would match if the request contained a baz query parameter.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=foo, ba.

This route would match if the request contained a foo query parameter whose value matched the ba. regexp, so bar and bazwould match.

RemoteAddr Route Predicate Factory

The RemoteAddr Route Predicate Factory takes a list (min size 1) of CIDR-notation (IPv4 or IPv6) strings, e.g. 192.168.0.1/16 (where 192.168.0.1 is an IP address and 16 is a subnet mask).

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: https://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24

This route would match if the remote address of the request was, for example, 192.168.1.10.

Modifying the way remote addresses are resolved

By default the RemoteAddr Route Predicate Factory uses the remote address from the incoming request. This may not match the actual client IP address if Spring Cloud Gateway sits behind a proxy layer.

You can customize the way that the remote address is resolved by setting a custom RemoteAddressResolver. Spring Cloud Gateway comes with one non-default remote address resolver which is based off of the X-Forwarded-For header, XForwardedRemoteAddressResolver.

XForwardedRemoteAddressResolver has two static constructor methods which take different approaches to security:

XForwardedRemoteAddressResolver::trustAll returns a RemoteAddressResolver which always takes the first IP address found in the X-Forwarded-For header. This approach is vulnerable to spoofing, as a malicious client could set an initial value for the X-Forwarded-For which would be accepted by the resolver.

XForwardedRemoteAddressResolver::maxTrustedIndex takes an index which correlates to the number of trusted infrastructure running in front of Spring Cloud Gateway. If Spring Cloud Gateway is, for example only accessible via HAProxy, then a value of 1 should be used. If two hops of trusted infrastructure are required before Spring Cloud Gateway is accessible, then a value of 2 should be used.

Given the following header value:

X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3

The maxTrustedIndex values below will yield the following remote addresses.

maxTrustedIndex result

[Integer.MIN_VALUE,0]

(invalid, IllegalArgumentException during initialization)

1

0.0.0.3

2

0.0.0.2

3

0.0.0.1

[4, Integer.MAX_VALUE]

0.0.0.1

Using Java config:

GatewayConfig.java

RemoteAddressResolver resolver = XForwardedRemoteAddressResolver
    .maxTrustedIndex(1);

...

.route("direct-route",
    r -> r.remoteAddr("10.1.1.1", "10.10.1.1/24")
        .uri("https://downstream1")
.route("proxied-route",
    r -> r.remoteAddr(resolver,  "10.10.1.1", "10.10.1.1/24")
        .uri("https://downstream2")
)

GatewayFilter Factories

Route filters allow the modification of the incoming HTTP request or outgoing HTTP response in some manner. Route filters are scoped to a particular route. Spring Cloud Gateway includes many built-in GatewayFilter Factories.

NOTE For more detailed examples on how to use any of the following filters, take a look at the unit tests.

AddRequestHeader GatewayFilter Factory

The AddRequestHeader GatewayFilter Factory takes a name and value parameter.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        - AddRequestHeader=X-Request-Foo, Bar

This will add X-Request-Foo:Bar header to the downstream request’s headers for all matching requests.

AddRequestParameter GatewayFilter Factory

The AddRequestParameter GatewayFilter Factory takes a name and value parameter.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: https://example.org
        filters:
        - AddRequestParameter=foo, bar

This will add foo=bar to the downstream request’s query string for all matching requests.

AddResponseHeader GatewayFilter Factory

The AddResponseHeader GatewayFilter Factory takes a name and value parameter.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: add_response_header_route
        uri: https://example.org
        filters:
        - AddResponseHeader=X-Response-Foo, Bar

This will add X-Response-Foo:Bar header to the downstream response’s headers for all matching requests.

DedupeResponseHeader GatewayFilter Factory

The DedupeResponseHeader GatewayFilter Factory takes a name parameter and an optional strategy parameter. name can contain a list of header names, space separated.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: dedupe_response_header_route
        uri: https://example.org
        filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

This will remove duplicate values of Access-Control-Allow-Credentials and Access-Control-Allow-Origin response headers in cases when both the gateway CORS logic and the downstream add them.

The DedupeResponseHeader filter also accepts an optional strategy parameter. The accepted values are RETAIN_FIRST (default), RETAIN_LAST, and RETAIN_UNIQUE.

Hystrix GatewayFilter Factory

Hystrix is a library from Netflix that implements the circuit breaker pattern. The Hystrix GatewayFilter allows you to introduce circuit breakers to your gateway routes, protecting your services from cascading failures and allowing you to provide fallback responses in the event of downstream failures.

To enable Hystrix GatewayFilters in your project, add a dependency on spring-cloud-starter-netflix-hystrix from Spring Cloud Netflix.

The Hystrix GatewayFilter Factory requires a single name parameter, which is the name of the HystrixCommand.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: hystrix_route
        uri: https://example.org
        filters:
        - Hystrix=myCommandName

This wraps the remaining filters in a HystrixCommand with command name myCommandName.

The Hystrix filter can also accept an optional fallbackUri parameter. Currently, only forward: schemed URIs are supported. If the fallback is called, the request will be forwarded to the controller matched by the URI.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: hystrix_route
        uri: lb://backing-service:8088
        predicates:
        - Path=/consumingserviceendpoint
        filters:
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackUri: forward:/incaseoffailureusethis
        - RewritePath=/consumingserviceendpoint, /backingserviceendpoint

This will forward to the /incaseoffailureusethis URI when the Hystrix fallback is called. Note that this example also demonstrates (optional) Spring Cloud Netflix Ribbon load-balancing via the lb prefix on the destination URI.

The primary scenario is to use the fallbackUri to an internal controller or handler within the gateway app. However, it is also possible to reroute the request to a controller or handler in an external application, like so:

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: ingredients
        uri: lb://ingredients
        predicates:
        - Path=//ingredients/**
        filters:
        - name: Hystrix
          args:
            name: fetchIngredients
            fallbackUri: forward:/fallback
      - id: ingredients-fallback
        uri: http://localhost:9994
        predicates:
        - Path=/fallback

In this example, there is no fallback endpoint or handler in the gateway application, however, there is one in another app, registered under http://localhost:9994.

In case of the request being forwarded to fallback, the Hystrix Gateway filter also provides the Throwable that has caused it. It’s added to the ServerWebExchange as the ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR attribute that can be used when handling the fallback within the gateway app.

For the external controller/ handler scenario, headers can be added with exception details. You can find more information on it in the FallbackHeaders GatewayFilter Factory section.

Hystrix settings (such as timeouts) can be configured with global defaults or on a route by route basis using application properties as explained on the Hystrix wiki.

To set a 5 second timeout for the example route above, the following configuration would be used:

application.yml

hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000

FallbackHeaders GatewayFilter Factory

The FallbackHeaders factory allows you to add Hystrix execution exception details in headers of a request forwarded to a fallbackUri in an external application, like in the following scenario:

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: ingredients
        uri: lb://ingredients
        predicates:
        - Path=//ingredients/**
        filters:
        - name: Hystrix
          args:
            name: fetchIngredients
            fallbackUri: forward:/fallback
      - id: ingredients-fallback
        uri: http://localhost:9994
        predicates:
        - Path=/fallback
        filters:
        - name: FallbackHeaders
          args:
            executionExceptionTypeHeaderName: Test-Header

In this example, after an execution exception occurs while running the HystrixCommand, the request will be forwarded to the fallback endpoint or handler in an app running on localhost:9994. The headers with the exception type, message and -if available- root cause exception type and message will be added to that request by the FallbackHeaders filter.

The names of the headers can be overwritten in the config by setting the values of the arguments listed below, along with their default values:

  • executionExceptionTypeHeaderName ("Execution-Exception-Type")

  • executionExceptionMessageHeaderName ("Execution-Exception-Message")

  • rootCauseExceptionTypeHeaderName ("Root-Cause-Exception-Type")

  • rootCauseExceptionMessageHeaderName ("Root-Cause-Exception-Message")

You can find more information on how Hystrix works with Gateway in the Hystrix GatewayFilter Factory section.

PrefixPath GatewayFilter Factory

The PrefixPath GatewayFilter Factory takes a single prefix parameter.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        - PrefixPath=/mypath

This will prefix /mypath to the path of all matching requests. So a request to /hello, would be sent to /mypath/hello.

PreserveHostHeader GatewayFilter Factory

The PreserveHostHeader GatewayFilter Factory has no parameters. This filter sets a request attribute that the routing filter will inspect to determine if the original host header should be sent, rather than the host header determined by the http client.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: preserve_host_route
        uri: https://example.org
        filters:
        - PreserveHostHeader

RequestRateLimiter GatewayFilter Factory

The RequestRateLimiter GatewayFilter Factory is uses a RateLimiter implementation to determine if the current request is allowed to proceed. If it is not, a status of HTTP 429 - Too Many Requests (by default) is returned.

This filter takes an optional keyResolver parameter and parameters specific to the rate limiter (see below).

keyResolver is a bean that implements the KeyResolver interface. In configuration, reference the bean by name using SpEL. #{@myKeyResolver} is a SpEL expression referencing a bean with the name myKeyResolver.

KeyResolver.java

public interface KeyResolver {
	Mono<String> resolve(ServerWebExchange exchange);
}

The KeyResolver interface allows pluggable strategies to derive the key for limiting requests. In future milestones, there will be some KeyResolver implementations.

The default implementation of KeyResolver is the PrincipalNameKeyResolver which retrieves the Principal from the ServerWebExchange and calls Principal.getName().

By default, if the KeyResolver does not find a key, requests will be denied. This behavior can be adjusted with the spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key (true or false) and spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code properties.

  The RequestRateLimiter is not configurable via the "shortcut" notation. The example below is invalid

application.properties

# INVALID SHORTCUT CONFIGURATION
spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}

Redis RateLimiter

The redis implementation is based off of work done at Stripe. It requires the use of the spring-boot-starter-data-redis-reactiveSpring Boot starter.

The algorithm used is the Token Bucket Algorithm.

The redis-rate-limiter.replenishRate is how many requests per second do you want a user to be allowed to do, without any dropped requests. This is the rate that the token bucket is filled.

The redis-rate-limiter.burstCapacity is the maximum number of requests a user is allowed to do in a single second. This is the number of tokens the token bucket can hold. Setting this value to zero will block all requests.

A steady rate is accomplished by setting the same value in replenishRate and burstCapacity. Temporary bursts can be allowed by setting burstCapacity higher than replenishRate. In this case, the rate limiter needs to be allowed some time between bursts (according to replenishRate), as 2 consecutive bursts will result in dropped requests (HTTP 429 - Too Many Requests).

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10
            redis-rate-limiter.burstCapacity: 20

Config.java

@Bean
KeyResolver userKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}

This defines a request rate limit of 10 per user. A burst of 20 is allowed, but the next second only 10 requests will be available. The KeyResolver is a simple one that gets the user request parameter (note: this is not recommended for production).

A rate limiter can also be defined as a bean implementing the RateLimiter interface. In configuration, reference the bean by name using SpEL. #{@myRateLimiter} is a SpEL expression referencing a bean with the name myRateLimiter.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            rate-limiter: "#{@myRateLimiter}"
            key-resolver: "#{@userKeyResolver}"

RedirectTo GatewayFilter Factory

The RedirectTo GatewayFilter Factory takes a status and a url parameter. The status should be a 300 series redirect http code, such as 301. The url should be a valid url. This will be the value of the Location header.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        - RedirectTo=302, https://acme.org

This will send a status 302 with a Location:https://acme.org header to perform a redirect.

RemoveHopByHopHeadersFilter GatewayFilter Factory

The RemoveHopByHopHeadersFilter GatewayFilter Factory removes headers from forwarded requests. The default list of headers that is removed comes from the IETF.

The default removed headers are:

  • Connection

  • Keep-Alive

  • Proxy-Authenticate

  • Proxy-Authorization

  • TE

  • Trailer

  • Transfer-Encoding

  • Upgrade

To change this, set the spring.cloud.gateway.filter.remove-non-proxy-headers.headers property to the list of header names to remove.

RemoveRequestHeader GatewayFilter Factory

The RemoveRequestHeader GatewayFilter Factory takes a name parameter. It is the name of the header to be removed.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: removerequestheader_route
        uri: https://example.org
        filters:
        - RemoveRequestHeader=X-Request-Foo

This will remove the X-Request-Foo header before it is sent downstream.

RemoveResponseHeader GatewayFilter Factory

The RemoveResponseHeader GatewayFilter Factory takes a name parameter. It is the name of the header to be removed.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: removeresponseheader_route
        uri: https://example.org
        filters:
        - RemoveResponseHeader=X-Response-Foo

This will remove the X-Response-Foo header from the response before it is returned to the gateway client.

To remove any kind of sensitive header you should configure this filter for any routes that you may want to do so. In addition you can configure this filter once using spring.cloud.gateway.default-filters and have it applied to all routes.

RewritePath GatewayFilter Factory

The RewritePath GatewayFilter Factory takes a path regexp parameter and a replacement parameter. This uses Java regular expressions for a flexible way to rewrite the request path.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: https://example.org
        predicates:
        - Path=/foo/**
        filters:
        - RewritePath=/foo/(?<segment>.*), /$\{segment}

For a request path of /foo/bar, this will set the path to /bar before making the downstream request. Notice the $\ which is replaced with $ because of the YAML spec.

RewriteResponseHeader GatewayFilter Factory

The RewriteResponseHeader GatewayFilter Factory takes nameregexp, and replacement parameters. It uses Java regular expressions for a flexible way to rewrite the response header value.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: rewriteresponseheader_route
        uri: https://example.org
        filters:
        - RewriteResponseHeader=X-Response-Foo, , password=[^&]+, password=***

For a header value of /42?user=ford&password=omg!what&flag=true, it will be set to /42?user=ford&password=***&flag=true after making the downstream request. Please use $\ to mean $ because of the YAML spec.

SaveSession GatewayFilter Factory

The SaveSession GatewayFilter Factory forces a WebSession::save operation before forwarding the call downstream. This is of particular use when using something like Spring Session with a lazy data store and need to ensure the session state has been saved before making the forwarded call.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: save_session
        uri: https://example.org
        predicates:
        - Path=/foo/**
        filters:
        - SaveSession

If you are integrating Spring Security with Spring Session, and want to ensure security details have been forwarded to the remote process, this is critical.

SecureHeaders GatewayFilter Factory

The SecureHeaders GatewayFilter Factory adds a number of headers to the response at the recommendation from this blog post.

The following headers are added (along with default values):

  • X-Xss-Protection:1; mode=block

  • Strict-Transport-Security:max-age=631138519

  • X-Frame-Options:DENY

  • X-Content-Type-Options:nosniff

  • Referrer-Policy:no-referrer

  • Content-Security-Policy:default-src ''self'' https:; font-src ''self'' https: data:; img-src ''self'' https: data:; object-src ''none''; script-src https:; style-src ''self'' https: ''unsafe-inline''

  • X-Download-Options:noopen

  • X-Permitted-Cross-Domain-Policies:none

To change the default values set the appropriate property in the spring.cloud.gateway.filter.secure-headers namespace:

Property to change:

  • xss-protection-header

  • strict-transport-security

  • frame-options

  • content-type-options

  • referrer-policy

  • content-security-policy

  • download-options

  • permitted-cross-domain-policies

To disable the default values set the property spring.cloud.gateway.filter.secure-headers.disable with comma separated values.

Example:

spring.cloud.gateway.filter.secure-headers.disable=frame-options,download-options

SetPath GatewayFilter Factory

The SetPath GatewayFilter Factory takes a path template parameter. It offers a simple way to manipulate the request path by allowing templated segments of the path. This uses the uri templates from Spring Framework. Multiple matching segments are allowed.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: setpath_route
        uri: https://example.org
        predicates:
        - Path=/foo/{segment}
        filters:
        - SetPath=/{segment}

For a request path of /foo/bar, this will set the path to /bar before making the downstream request.

SetResponseHeader GatewayFilter Factory

The SetResponseHeader GatewayFilter Factory takes name and value parameters.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: setresponseheader_route
        uri: https://example.org
        filters:
        - SetResponseHeader=X-Response-Foo, Bar

This GatewayFilter replaces all headers with the given name, rather than adding. So if the downstream server responded with a X-Response-Foo:1234, this would be replaced with X-Response-Foo:Bar, which is what the gateway client would receive.

SetStatus GatewayFilter Factory

The SetStatus GatewayFilter Factory takes a single status parameter. It must be a valid Spring HttpStatus. It may be the integer value 404 or the string representation of the enumeration NOT_FOUND.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: setstatusstring_route
        uri: https://example.org
        filters:
        - SetStatus=BAD_REQUEST
      - id: setstatusint_route
        uri: https://example.org
        filters:
        - SetStatus=401

In either case, the HTTP status of the response will be set to 401.

StripPrefix GatewayFilter Factory

The StripPrefix GatewayFilter Factory takes one parameter, parts. The parts parameter indicated the number of parts in the path to strip from the request before sending it downstream.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: nameRoot
        uri: https://nameservice
        predicates:
        - Path=/name/**
        filters:
        - StripPrefix=2

When a request is made through the gateway to /name/bar/foo the request made to nameservice will look like https://nameservice/foo.

Retry GatewayFilter Factory

The Retry GatewayFilter Factory takes retriesstatusesmethods, and series as parameters.

  • retries: the number of retries that should be attempted

  • statuses: the HTTP status codes that should be retried, represented using org.springframework.http.HttpStatus

  • methods: the HTTP methods that should be retried, represented using org.springframework.http.HttpMethod

  • series: the series of status codes to be retried, represented using org.springframework.http.HttpStatus.Series

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: retry_test
        uri: http://localhost:8080/flakey
        predicates:
        - Host=*.retry.com
        filters:
        - name: Retry
          args:
            retries: 3
            statuses: BAD_GATEWAY
  The retry filter does not currently support retrying with a body (e.g. for POST or PUT requests with a body).
  When using the retry filter with a forward: prefixed URL, the target endpoint should be written carefully so that in case of an error it does not do anything that could result in a response being sent to the client and committed. For example, if the target endpoint is an annotated controller, the target controller method should not return ResponseEntity with an error status code. Instead it should throw an Exception, or signal an error, e.g. via a Mono.error(ex) return value, which the retry filter can be configured to handle by retrying.

RequestSize GatewayFilter Factory

The RequestSize GatewayFilter Factory can restrict a request from reaching the downstream service , when the request size is greater than the permissible limit. The filter takes RequestSize as parameter which is the permissible size limit of the request defined in bytes.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: request_size_route
      uri: http://localhost:8080/upload
      predicates:
      - Path=/upload
      filters:
      - name: RequestSize
        args:
          maxSize: 5000000

The RequestSize GatewayFilter Factory set the response status as 413 Payload Too Large with a additional header errorMessagewhen the Request is rejected due to size. Following is an example of such an errorMessage .

errorMessage : Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB

  The default Request size will be set to 5 MB if not provided as filter argument in route definition.

Modify Request Body GatewayFilter Factory

This filter is considered BETA and the API may change in the future

This filter can be used to modify the request body before it is sent downstream by the Gateway.

  This filter can only be configured using the Java DSL
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org")
            .filters(f -> f.prefixPath("/httpbin")
                .modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
                    (exchange, s) -> return Mono.just(new Hello(s.toUpperCase())))).uri(uri))
        .build();
}

static class Hello {
    String message;

    public Hello() { }

    public Hello(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

Modify Response Body GatewayFilter Factory

This filter is considered BETA and the API may change in the future

This filter can be used to modify the response body before it is sent back to the Client.

  This filter can only be configured using the Java DSL
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org")
            .filters(f -> f.prefixPath("/httpbin")
        		.modifyResponseBody(String.class, String.class,
        		    (exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri)
        .build();
}

Default Filters

If you would like to add a filter and apply it to all routes you can use spring.cloud.gateway.default-filters. This property takes a list of filters

application.yml

spring:
  cloud:
    gateway:
      default-filters:
      - AddResponseHeader=X-Response-Default-Foo, Default-Bar
      - PrefixPath=/httpbin

Global Filters

The GlobalFilter interface has the same signature as GatewayFilter. These are special filters that are conditionally applied to all routes. (This interface and usage are subject to change in future milestones).

Combined Global Filter and GatewayFilter Ordering

When a request comes in (and matches a Route) the Filtering Web Handler will add all instances of GlobalFilter and all route specific instances of GatewayFilter to a filter chain. This combined filter chain is sorted by the org.springframework.core.Orderedinterface, which can be set by implementing the getOrder() method or by using the @Order annotation.

As Spring Cloud Gateway distinguishes between "pre" and "post" phases for filter logic execution (see: How It Works), the filter with the highest precedence will be the first in the "pre"-phase and the last in the "post"-phase.

ExampleConfiguration.java

@Bean
@Order(-1)
public GlobalFilter a() {
    return (exchange, chain) -> {
        log.info("first pre filter");
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            log.info("third post filter");
        }));
    };
}

@Bean
@Order(0)
public GlobalFilter b() {
    return (exchange, chain) -> {
        log.info("second pre filter");
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            log.info("second post filter");
        }));
    };
}

@Bean
@Order(1)
public GlobalFilter c() {
    return (exchange, chain) -> {
        log.info("third pre filter");
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            log.info("first post filter");
        }));
    };
}

Forward Routing Filter

The ForwardRoutingFilter looks for a URI in the exchange attribute ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR. If the url has a forward scheme (ie forward:///localendpoint), it will use the Spring DispatcherHandler to handler the request. The path part of the request URL will be overridden with the path in the forward URL. The unmodified original url is appended to the list in the ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR attribute.

LoadBalancerClient Filter

The LoadBalancerClientFilter looks for a URI in the exchange attribute ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR. If the url has a lb scheme (ie lb://myservice), it will use the Spring Cloud LoadBalancerClient to resolve the name (myservice in the previous example) to an actual host and port and replace the URI in the same attribute. The unmodified original url is appended to the list in the ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR attribute. The filter will also look in the ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR attribute to see if it equals lb and then the same rules apply.

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: myRoute
        uri: lb://service
        predicates:
        - Path=/service/**
  By default when a service instance cannot be found in the LoadBalancer a 503 will be returned. You can configure the Gateway to return a 404 by setting spring.cloud.gateway.loadbalancer.use404=true.
  The isSecure value of the ServiceInstance returned from the LoadBalancer will override the scheme specified in the request made to the Gateway. For example, if the request comes into the Gateway over HTTPS but the ServiceInstance indicates it is not secure, then the downstream request will be made over HTTP. The opposite situation can also apply. However if GATEWAY_SCHEME_PREFIX_ATTR is specified for the route in the Gateway configuration, the prefix will be stripped and the resulting scheme from the route URL will override the ServiceInstance configuration.

Netty Routing Filter

The Netty Routing Filter runs if the url located in the ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange attribute has a http or https scheme. It uses the Netty HttpClient to make the downstream proxy request. The response is put in the ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR exchange attribute for use in a later filter. (There is an experimental WebClientHttpRoutingFilter that performs the same function, but does not require netty)

Netty Write Response Filter

The NettyWriteResponseFilter runs if there is a Netty HttpClientResponse in the ServerWebExchangeUtils.CLIENT_RESPONSE_ATTRexchange attribute. It is run after all other filters have completed and writes the proxy response back to the gateway client response. (There is an experimental WebClientWriteResponseFilter that performs the same function, but does not require netty)

RouteToRequestUrl Filter

The RouteToRequestUrlFilter runs if there is a Route object in the ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR exchange attribute. It creates a new URI, based off of the request URI, but updated with the URI attribute of the Route object. The new URI is placed in the ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange attribute`.

If the URI has a scheme prefix, such as lb:ws://serviceid, the lb scheme is stripped from the URI and placed in the ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR for use later in the filter chain.

Websocket Routing Filter

The Websocket Routing Filter runs if the url located in the ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange attribute has a ws or wss scheme. It uses the Spring Web Socket infrastructure to forward the Websocket request downstream.

Websockets may be load-balanced by prefixing the URI with lb, such as lb:ws://serviceid.

  If you are using SockJS as a fallback over normal http, you should configure a normal HTTP route as well as the Websocket Route.

application.yml

spring:
  cloud:
    gateway:
      routes:
      # SockJS route
      - id: websocket_sockjs_route
        uri: http://localhost:3001
        predicates:
        - Path=/websocket/info/**
      # Normwal Websocket route
      - id: websocket_route
        uri: ws://localhost:3001
        predicates:
        - Path=/websocket/**

Gateway Metrics Filter

To enable Gateway Metrics add spring-boot-starter-actuator as a project dependency. Then, by default, the Gateway Metrics Filter runs as long as the property spring.cloud.gateway.metrics.enabled is not set to false. This filter adds a timer metric named "gateway.requests" with the following tags:

  • routeId: The route id

  • routeUri: The URI that the API will be routed to

  • outcome: Outcome as classified by HttpStatus.Series

  • status: Http Status of the request returned to the client

  • httpStatusCode: Http Status of the request returned to the client

  • httpMethod: The Http method used for the request

These metrics are then available to be scraped from /actuator/metrics/gateway.requests and can be easily integated with Prometheus to create a Grafana dashboard.

  To enable the pometheus endpoint add micrometer-registry-prometheus as a project dependency.

Marking An Exchange As Routed

After the Gateway has routed a ServerWebExchange it will mark that exchange as "routed" by adding gatewayAlreadyRouted to the exchange attributes. Once a request has been marked as routed, other routing filters will not route the request again, essentially skipping the filter. There are convenience methods that you can use to mark an exchange as routed or check if an exchange has already been routed.

  • ServerWebExchangeUtils.isAlreadyRouted takes a ServerWebExchange object and checks if it has been "routed"

  • ServerWebExchangeUtils.setAlreadyRouted takes a ServerWebExchange object and marks it as "routed"

TLS / SSL

The Gateway can listen for requests on https by following the usual Spring server configuration. Example:

application.yml

server:
  ssl:
    enabled: true
    key-alias: scg
    key-store-password: scg1234
    key-store: classpath:scg-keystore.p12
    key-store-type: PKCS12

Gateway routes can be routed to both http and https backends. If routing to a https backend then the Gateway can be configured to trust all downstream certificates with the following configuration:

application.yml

spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          useInsecureTrustManager: true

Using an insecure trust manager is not suitable for production. For a production deployment the Gateway can be configured with a set of known certificates that it can trust with the following configuration:

application.yml

spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          trustedX509Certificates:
          - cert1.pem
          - cert2.pem

If the Spring Cloud Gateway is not provisioned with trusted certificates the default trust store is used (which can be overridden with system property javax.net.ssl.trustStore).

TLS Handshake

The Gateway maintains a client pool that it uses to route to backends. When communicating over https the client initiates a TLS handshake. A number of timeouts are associated with this handshake. These timeouts can be configured (defaults shown):

application.yml

spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          handshake-timeout-millis: 10000
          close-notify-flush-timeout-millis: 3000
          close-notify-read-timeout-millis: 0

Configuration

Configuration for Spring Cloud Gateway is driven by a collection of `RouteDefinitionLocator`s.

RouteDefinitionLocator.java

public interface RouteDefinitionLocator {
	Flux<RouteDefinition> getRouteDefinitions();
}

By default, a PropertiesRouteDefinitionLocator loads properties using Spring Boot’s @ConfigurationProperties mechanism.

The configuration examples above all use a shortcut notation that uses positional arguments rather than named ones. The two examples below are equivalent:

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: setstatus_route
        uri: https://example.org
        filters:
        - name: SetStatus
          args:
            status: 401
      - id: setstatusshortcut_route
        uri: https://example.org
        filters:
        - SetStatus=401

For some usages of the gateway, properties will be adequate, but some production use cases will benefit from loading configuration from an external source, such as a database. Future milestone versions will have RouteDefinitionLocatorimplementations based off of Spring Data Repositories such as: Redis, MongoDB and Cassandra.

Fluent Java Routes API

To allow for simple configuration in Java, there is a fluent API defined in the RouteLocatorBuilder bean.

GatewaySampleApplication.java

// static imports from GatewayFilters and RoutePredicates
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder, ThrottleGatewayFilterFactory throttle) {
    return builder.routes()
            .route(r -> r.host("**.abc.org").and().path("/image/png")
                .filters(f ->
                        f.addResponseHeader("X-TestHeader", "foobar"))
                .uri("http://httpbin.org:80")
            )
            .route(r -> r.path("/image/webp")
                .filters(f ->
                        f.addResponseHeader("X-AnotherHeader", "baz"))
                .uri("http://httpbin.org:80")
            )
            .route(r -> r.order(-1)
                .host("**.throttle.org").and().path("/get")
                .filters(f -> f.filter(throttle.apply(1,
                        1,
                        10,
                        TimeUnit.SECONDS)))
                .uri("http://httpbin.org:80")
            )
            .build();
}

This style also allows for more custom predicate assertions. The predicates defined by RouteDefinitionLocator beans are combined using logical and. By using the fluent Java API, you can use the and()or() and negate() operators on the Predicateclass.

DiscoveryClient Route Definition Locator

The Gateway can be configured to create routes based on services registered with a DiscoveryClient compatible service registry.

To enable this, set spring.cloud.gateway.discovery.locator.enabled=true and make sure a DiscoveryClient implementation is on the classpath and enabled (such as Netflix Eureka, Consul or Zookeeper).

Configuring Predicates and Filters For DiscoveryClient Routes

By default the Gateway defines a single predicate and filter for routes created via a DiscoveryClient.

The default predicate is a path predicate defined with the pattern /serviceId/**, where serviceId is the id of the service from the DiscoveryClient.

The default filter is rewrite path filter with the regex /serviceId/(?<remaining>.*) and the replacement /${remaining}. This just strips the service id from the path before the request is sent downstream.

If you would like to customize the predicates and/or filters used by the DiscoveryClient routes you can do so by setting spring.cloud.gateway.discovery.locator.predicates[x] and spring.cloud.gateway.discovery.locator.filters[y]. When doing so you need to make sure to include the default predicate and filter above, if you want to retain that functionality. Below is an example of what this looks like.

application.properties

spring.cloud.gateway.discovery.locator.predicates[0].name: Path
spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "''/''+serviceId+''/**''"
spring.cloud.gateway.discovery.locator.predicates[1].name: Host
spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "''**.foo.com''"
spring.cloud.gateway.discovery.locator.filters[0].name: Hystrix
spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
spring.cloud.gateway.discovery.locator.filters[1].name: RewritePath
spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "''/'' + serviceId + ''/(?<remaining>.*)''"
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "''/${remaining}''"

Reactor Netty Access Logs

To enable Reactor Netty access logs, set -Dreactor.netty.http.server.accessLogEnabled=true. (It must be a Java System Property, not a Spring Boot property).

The logging system can be configured to have a separate access log file. Below is an example logback configuration:

logback.xml

    <appender name="accessLog" class="ch.qos.logback.core.FileAppender">
        <file>access_log.log</file>
        <encoder>
            <pattern>%msg%n</pattern>
        </encoder>
    </appender>
    <appender name="async" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="accessLog" />
    </appender>

    <logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
        <appender-ref ref="async"/>
    </logger>

CORS Configuration

The gateway can be configured to control CORS behavior. The "global" CORS configuration is a map of URL patterns to Spring Framework CorsConfiguration.

application.yml

spring:
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          ''[/**]'':
            allowedOrigins: "https://docs.spring.io"
            allowedMethods:
            - GET

In the example above, CORS requests will be allowed from requests that originate from docs.spring.io for all GET requested paths.

Actuator API

The /gateway actuator endpoint allows to monitor and interact with a Spring Cloud Gateway application. To be remotely accessible, the endpoint has to be enabled and exposed via HTTP or JMX in the application properties.

application.properties

management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway

Retrieving route filters

Global Filters

To retrieve the global filters applied to all routes, make a GET request to /actuator/gateway/globalfilters. The resulting response is similar to the following:

{
  "org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@77856cc5": 10100,
  "org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@4f6fd101": 10000,
  "org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@32d22650": -1,
  "org.springframework.cloud.gateway.filter.ForwardRoutingFilter@106459d9": 2147483647,
  "org.springframework.cloud.gateway.filter.NettyRoutingFilter@1fbd5e0": 2147483647,
  "org.springframework.cloud.gateway.filter.ForwardPathFilter@33a71d23": 0,
  "org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@135064ea": 2147483637,
  "org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@23c05889": 2147483646
}

The response contains details of the global filters in place. For each global filter is provided the string representation of the filter object (e.g., org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@77856cc5) and the corresponding order in the filter chain.

Route Filters

To retrieve the GatewayFilter factories applied to routes, make a GET request to /actuator/gateway/routefilters. The resulting response is similar to the following:

{
  "[AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null,
  "[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]": null,
  "[SaveSessionGatewayFilterFactory@4449b273 configClass = Object]": null
}

The response contains details of the GatewayFilter factories applied to any particular route. For each factory is provided the string representation of the corresponding object (e.g., [SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]). Note that the null value is due to an incomplete implementation of the endpoint controller, for that it tries to set the order of the object in the filter chain, which does not apply to a GatewayFilter factory object.

Refreshing the route cache

To clear the routes cache, make a POST request to /actuator/gateway/refresh. The request returns a 200 without response body.

Retrieving the routes defined in the gateway

To retrieve the routes defined in the gateway, make a GET request to /actuator/gateway/routes. The resulting response is similar to the following:

[{
  "route_id": "first_route",
  "route_object": {
    "predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@1e9d7e7d",
    "filters": [
      "OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory$$Lambda$436/674480275@6631ef72, order=0}"
    ]
  },
  "order": 0
},
{
  "route_id": "second_route",
  "route_object": {
    "predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@cd8d298",
    "filters": []
  },
  "order": 0
}]

The response contains details of all the routes defined in the gateway. The following table describes the structure of each element (i.e., a route) of the response.

Path Type Description

route_id

String

The route id.

route_object.predicate

Object

The route predicate.

route_object.filters

Array

The GatewayFilter factories applied to the route.

order

Number

The route order.

Retrieving information about a particular route

To retrieve information about a single route, make a GET request to /actuator/gateway/routes/{id} (e.g., /actuator/gateway/routes/first_route). The resulting response is similar to the following:

{
  "id": "first_route",
  "predicates": [{
    "name": "Path",
    "args": {"_genkey_0":"/first"}
  }],
  "filters": [],
  "uri": "https://www.uri-destination.org",
  "order": 0
}]

The following table describes the structure of the response.

Path Type Description

id

String

The route id.

predicates

Array

The collection of route predicates. Each item defines the name and the arguments of a given predicate.

filters

Array

The collection of filters applied to the route.

uri

String

The destination URI of the route.

order

Number

The route order.

Creating and deleting a particular route

To create a route, make a POST request to /gateway/routes/{id_route_to_create} with a JSON body that specifies the fields of the route (see the previous subsection).

To delete a route, make a DELETE request to /gateway/routes/{id_route_to_delete}.

Recap: list of all endpoints

The table below summarises the Spring Cloud Gateway actuator endpoints. Note that each endpoint has /actuator/gateway as the base-path.

ID HTTP Method Description

globalfilters

GET

Displays the list of global filters applied to the routes.

routefilters

GET

Displays the list of GatewayFilter factories applied to a particular route.

refresh

POST

Clears the routes cache.

routes

GET

Displays the list of routes defined in the gateway.

routes/{id}

GET

Displays information about a particular route.

routes/{id}

POST

Add a new route to the gateway.

routes/{id}

DELETE

Remove an existing route from the gateway.

Developer Guide

TODO: overview of writing custom integrations

Writing Custom Route Predicate Factories

TODO: document writing Custom Route Predicate Factories

Writing Custom GatewayFilter Factories

In order to write a GatewayFilter you will need to implement GatewayFilterFactory. There is an abstract class called AbstractGatewayFilterFactory which you can extend.

PreGatewayFilterFactory.java

public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {

	public PreGatewayFilterFactory() {
		super(Config.class);
	}

	@Override
	public GatewayFilter apply(Config config) {
		// grab configuration from Config object
		return (exchange, chain) -> {
            //If you want to build a "pre" filter you need to manipulate the
            //request before calling chain.filter
            ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
            //use builder to manipulate the request
            return chain.filter(exchange.mutate().request(request).build());
		};
	}

	public static class Config {
        //Put the configuration properties for your filter here
	}

}

PostGatewayFilterFactory.java

public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {

	public PostGatewayFilterFactory() {
		super(Config.class);
	}

	@Override
	public GatewayFilter apply(Config config) {
		// grab configuration from Config object
		return (exchange, chain) -> {
			return chain.filter(exchange).then(Mono.fromRunnable(() -> {
				ServerHttpResponse response = exchange.getResponse();
				//Manipulate the response in some way
			}));
		};
	}

	public static class Config {
        //Put the configuration properties for your filter here
	}

}

Writing Custom Global Filters

In order to write a custom global filter, you will need to implement GlobalFilter interface. This will apply the filter to all requests.

Example of how to set up a Global Pre and Post filter, respectively

@Bean
public GlobalFilter customGlobalFilter() {
    return (exchange, chain) -> exchange.getPrincipal()
        .map(Principal::getName)
        .defaultIfEmpty("Default User")
        .map(userName -> {
          //adds header to proxied request
          exchange.getRequest().mutate().header("CUSTOM-REQUEST-HEADER", userName).build();
          return exchange;
        })
        .flatMap(chain::filter);
}

@Bean
public GlobalFilter customGlobalPostFilter() {
    return (exchange, chain) -> chain.filter(exchange)
        .then(Mono.just(exchange))
        .map(serverWebExchange -> {
          //adds header to response
          serverWebExchange.getResponse().getHeaders().set("CUSTOM-RESPONSE-HEADER",
              HttpStatus.OK.equals(serverWebExchange.getResponse().getStatusCode()) ? "It worked": "It did not work");
          return serverWebExchange;
        })
        .then();
}

Writing Custom Route Locators and Writers

TODO: document writing Custom Route Locators and Writers

Building a Simple Gateway Using Spring MVC or Webflux

Spring Cloud Gateway provides a utility object called ProxyExchange which you can use inside a regular Spring web handler as a method parameter. It supports basic downstream HTTP exchanges via methods that mirror the HTTP verbs. With MVC it also supports forwarding to a local handler via the forward() method. To use the ProxyExchange just include the right module in your classpath (either spring-cloud-gateway-mvc or spring-cloud-gateway-webflux).

MVC example (proxying a request to "/test" downstream to a remote server):

@RestController
@SpringBootApplication
public class GatewaySampleApplication {

	@Value("${remote.home}")
	private URI home;

	@GetMapping("/test")
	public ResponseEntity<?> proxy(ProxyExchange<byte[]> proxy) throws Exception {
		return proxy.uri(home.toString() + "/image/png").get();
	}

}

The same thing with Webflux:

@RestController
@SpringBootApplication
public class GatewaySampleApplication {

	@Value("${remote.home}")
	private URI home;

	@GetMapping("/test")
	public Mono<ResponseEntity<?>> proxy(ProxyExchange<byte[]> proxy) throws Exception {
		return proxy.uri(home.toString() + "/image/png").get();
	}

}

There are convenience methods on the ProxyExchange to enable the handler method to discover and enhance the URI path of the incoming request. For example you might want to extract the trailing elements of a path to pass them downstream:

@GetMapping("/proxy/path/**")
public ResponseEntity<?> proxyPath(ProxyExchange<byte[]> proxy) throws Exception {
  String path = proxy.path("/proxy/path/");
  return proxy.uri(home.toString() + "/foos/" + path).get();
}

All the features of Spring MVC or Webflux are available to Gateway handler methods. So you can inject request headers and query parameters, for instance, and you can constrain the incoming requests with declarations in the mapping annotation. See the documentation for @RequestMapping in Spring MVC for more details of those features.

Headers can be added to the downstream response using the header() methods on ProxyExchange.

You can also manipulate response headers (and anything else you like in the response) by adding a mapper to the get() etc. method. The mapper is a Function that takes the incoming ResponseEntity and converts it to an outgoing one.

First class support is provided for "sensitive" headers ("cookie" and "authorization" by default) which are not passed downstream, and for "proxy" headers (x-forwarded-*).

Fizz Gateway基准测试性能超越Spring Cloud Gateway

Fizz Gateway基准测试性能超越Spring Cloud Gateway

基准测试结果

我们将Fizz与Spring官方spring-cloud-gateway进行比较,使用相同的环境和条件,测试对象均为单个节点。

产品 QPS 90% Latency(ms)
直接访问后端服务 9087.46 10.76
fizz-gateway 5927.13 19.86
spring-cloud-gateway 5044.04 22.91

#基准测试详情

#硬件环境

后端服务所在服务器:

4核8G内存

Intel(R) Xeon(R) CPU X5675 @ 3.07GHz * 4

Linux version 3.10.0-327.el7.x86_64

节点所在服务器:

4核8G内存

Intel(R) Xeon(R) CPU X5675 @ 3.07GHz * 4

Linux version 3.10.0-327.el7.x86_64

压测程序所在服务器:

4核8G内存

Intel(R) Xeon(R) CPU X5675 @ 3.07GHz * 4

Linux version 3.10.0-327.el7.x86_64

#压测工具

压测软件:wrk

并发连接: 100

#压测结果截图

  • 直接访问后端服务: 

  • fizz-gateway:

 

  • spring-cloud-gateway:

 

 

Spring cloud - gateway

Spring cloud - gateway

什么是Spring Cloud Gateway

先去看下官网的解释:

This project provides an API Gateway built on top of the Spring Ecosystem, including: Spring 6, Spring Boot 3 and Project Reactor. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency.

Spring提供了一个API网关,基于Spring 6、Spring Boot 3以及Project Reactor。目标是提供一个简单、有效的方式进行API路由,以及安全、监控等众多项目的公共需求。

这个描述其实很简单,但是我们需要了解一个背景知识:安全、权限、监控、系统弹性等需求是每一个系统或模块的公共需求,这类需求的解决方案可以是在每一个模块中处理,但显而易见的弊端是相同的处理逻辑会在每一个模块中重复实现,增加系统的复杂性,降低系统的可维护性。

Spring Cloud Gateway可以完美解决以上问题,集中处理鉴权、安全、监控、流量监控等公共需求,并可实现对最终用户隐藏真实的业务调用接口,避免业务接口的细节的对外暴露。

术语

  1. route:路由,是网关的基本概念,由路由ID、目标URI、一组断言以及一组过滤器组成,断言判断为true则表示当前路由被匹配。
  2. Predicate:断言,是一个java 8函数式断言接口,输入是Spring framework的ServerWebExchange。由于ServerWebExchange包含了http request以及http response,所以,断言可以基于任何http request设置,比如http header、http请求参数等等。
  3. Filter:过滤器,Spring Cloud Gateway基于GatewayFilter接口、通过特定的过滤器工厂创建的一系列实例,在请求发送给网关后的服务前、或者调用网关后面的服务后执行,从而可以实现修改请求参数及返回信息等增强功能。

Spring Cloud Gateway如何工作

下图展示了Spring Cloud网关的工作原理:
在这里插入图片描述
客户端发送请求给spring cloud网关而不是真实的业务服务端(这种情况下网关的作用类似于反向代理nginx),网关的Gateway Handle Mapping判断Predicate符合的话在转发请求给Gateway Web Handle,之后Gateway Web Handle调用Filters处理后将请求发送给被代理的各业务服务(网关uri定义的)。

有没有发现上图比较眼熟?是不是和Servlet+Spring MVC处理请求的过程很类似?

Filters组成filters chain,像剥洋葱一样逐个调用,先执行各过滤器的before逻辑,调用完Proxied Service之后再执行after逻辑。

引入Spring Cloud Gateway

我们在前面案例的基础上,增加Spring Cloud Gateway模块。

新建一个Springgateway模块:
在这里插入图片描述

项目中引入Spring Cloud Gateway,pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springCloud</artifactId>
        <groupId>com.example</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springgateway</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

</project>

注意Spring Cloud Gateway不能是SpringMVC项目,所以pom文件中不能引入spring-boot-starter-web,否则项目启动不了。

然后配置yam文件:

spring:
  application:
    name: spring-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://127.0.0.1:9090
          predicates:
            - Path=/order/*
eureka:
  client:
    service-url: # eureka service
      defaultZone: http://127.0.0.1:10086/eureka/
server:
  port: 9095

在applicaton.yml文件中配置一个route:
id: 任意一个名字就可以,但是需要唯一。
uri:断言判断匹配成功之后的路由地址,指向proxied service
predicates:断言,配置为Path断言,判断请求路径中是否包含/order

Spring Cloud Gateway提供了很多断言工厂:
在这里插入图片描述
我们的案例使用path断言工厂,path断言工厂负责根据请求路径进行匹配。

我们把Spring Cloud Gateway也配置为Eureka客户端,放在注册中心统一管理,后面我们可以看到,Spring Cloud Gateway支持通过注册中心进行路由。

上面的配置很简单,判断请求路径中如果包含/order的话,将请求路由到http://127.0.0.1:9090去处理。

验证

依次启动Eureka、orderservice、orderservice以及springGateway service:
在这里插入图片描述
gateway启动在端口9095,端都9090是orderservice。

看一下10086端口的Eureka注册中心:

在这里插入图片描述
发现orderservice、userservice以及spring-gateway都已经在Eureka注册中心完成注册。

接下来访问9095端口的gateway服务:
在这里插入图片描述
说明Spring Cloud Gateway已经开始正常工作了,能够路由的orderservice服务。

改造orderservice服务

上面路由配置直接指向了 http://127.0.0.1:9090,只能访问到指定的应用,无法访问到spring loadbalance提供的负载均衡服务。

下面我们尝试通过注册中心访问服务、并享受到spring loadbalance提供的负载均衡服务。

前面的案例访问orderservice后,会通过orderservice访问userservice的服务。现在我们是为了验证gateway,简单起见,我们暂时去掉userservice,通过网关gateway访问orderservice、由orderservice直接提供服务,不再访问userservice了。

为此,简单改造一下orderservice的orderController,不再调用userservice了,直接返回当前orderservice的端口:

package com.example.controller;

@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController {

    @Value("${server.port}")
    private String serverPort;

    @Autowired
    OrderService orderService;
    @Autowired
    FallbackHandle fallbackHandle;
    @GetMapping("/getOrder")

    @HystrixCommand(fallbackMethod = "fallback",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
    })
    public String getOrder(){
        log.info("Come here to get Order....123===");
        return "order service from:"+serverPort;
//        return orderService.getOrder();
    }

    public String fallback(){
        return "orderService服务异常";
    }

}

重新启动服务,访问网关:
在这里插入图片描述
说明网关服务、以及改造后的orderservice都能正常工作了。

增加一个orderservice服务

copy一份orderservice的配置,在9091端口再启动一个orderservice服务:
在这里插入图片描述
启动服务后,检查Eureka注册中心:
在这里插入图片描述
发现9090/9091端口分别由一个orderservice注册到了Eureka注册中心。

通过注册中心配置网关

下面我们修改一下网关服务的配置:

spring:
  application:
    name: spring-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: lb://orderservice
          predicates:
            - Path=/order/*
eureka:
  client:
    service-url: # eureka service
      defaultZone: http://127.0.0.1:10086/eureka/
server:
  port: 9095

断言匹配成功后,通过Eureka注册中心以及loadbalance路由到orderservice服务。

启动服务,访问验证:
在这里插入图片描述
在这里插入图片描述
可以发现,不需要太多的配置,Spring Cloud Gateway已经可以通过Spring Eureka注册中心获取到注册的服务、并通过Spring LoadBalance负载均衡策略访问到服务了。

通过简单的配置,我们现在的应用其实已经具备了微服务的注册中心、负载均衡、网关等强大能力了!

过滤器

过滤器的作用原理我们在开篇说过了,过滤器可以修改请求的request或response,或者对请求进行某种控制,从而实现众多附加功能,比如修改头信息、修改请求参数、权限验证、超时控制等等。

Spring Cloud Gateway的过滤去分为路由过滤器和全局过滤器,路由过滤器作用范围是当前匹配到的路由,全局过滤器的作用范围是全局(所有路由)。

Spring Cloud Gateway提供了众多内置的路由过滤器:
在这里插入图片描述
以及内置的全局过滤器:
在这里插入图片描述
当请求匹配之后,路由过滤器以及全局过滤器会被装配成filterChain,filterChain装配的过程中,过滤器会按照org.springframework.core.Ordered接口进行排序,按顺序调用。

As Spring Cloud Gateway distinguishes between “pre” and “post” phases for filter logic execution (see How it Works), the filter with the highest precedence is the first in the “pre”-phase and the last in the “post”-phase.

高优先级的过滤器意味着早一些被 pre-phase阶段调用、晚一些被post-phase阶段调用。也就是说,高优先级针对的是请求服务之前的处理,和Servlet的过滤器的优先顺序类似。

除了Spring Cloud Gateway提供的内置过滤器之外,我们还可以实现自己的过滤器。

实现自己的过滤器

我们可以通过实现接口GatewayFilterFactory从而实现自己的路由过滤器。

Spring Cloud Filter提供了一个虚拟类AbstractGatewayFilterFactory,我们可以扩展该类实现自己的路由过滤器,比如我们创建一个MyGatewayFilterFactory :

package com.example.filter;

@Component
@Slf4j
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {

    public MyGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
         log.info("filter:"+config.getName());
        return (exchange, chain) -> {
            //If you want to build a "pre" filter you need to manipulate the
            //request before calling chain.filter
            //获取request
            ServerHttpRequest request = exchange.getRequest();
            //从request中获取用户信息,进行用户鉴权......之后

            log.info("This is pre filter===");
            return chain.filter(exchange).then(Mono.fromRunnable(()-> {
                ServerHttpResponse response = exchange.getResponse();
                response.getHeaders().add("Auth","xxxx.yyyy.zzzz");
                log.info("this is after filter");
            }));
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

}

需要通过@Component注解将过滤器加入到Spring容器中。

通过Config接收一个name参数,在apply方法中可以实现路由前置、以及路由后置过滤逻辑。我们的MyGatewayFilterFactory 同时实现了前置逻辑和后置逻辑,前置逻辑中可以添加用户鉴权等代码,简单起见,我们只是log打印一句话。后置逻辑中同样很简单,打印一句话,设置一个reponse header。

配置路由过滤器

上面我们实现的是漏油过滤器,所以只有配置在某一路由上才会生效:

spring:
  application:
    name: spring-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
#          uri: http://127.0.0.1:9090
          uri: lb://orderservice
          predicates:
            - Path=/order/*
          filters:
            - name: My
              args:
                name: My own pre-filter
eureka:
  client:
    service-url: # eureka service
      defaultZone: http://127.0.0.1:10086/eureka/
server:
  port: 9095

启动服务,测试:
在这里插入图片描述
首先从前端请求中发现response header已经成功添加。然后看一下后台log:
在这里插入图片描述
我们自己的路由过滤器已经可以正常工作了。

添加自己的全局过滤器

全局过滤器需要实现GlobalFilter 接口:

package com.example.filter;

@Component
@Slf4j
public class MyGlobalGatewayFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("Here i can do anything to exchage");
        return chain.filter(exchange).then(Mono.just(exchange)).map(serverWebExchange->{
            serverWebExchange.getResponse().getHeaders().add("Global-Filter","Global filter OK");
            return serverWebExchange;
        }).then();

    }
}

同样,我们添加的MyGlobalGatewayFilter 同时实现前置和后置过滤逻辑,不过都非常简单,前置过滤逻辑只是打印一段话,后置过滤逻辑添加一个response header。

全局过滤器是不需要额外配置的,对所有router都生效。

重新启动gateway,测试:
在这里插入图片描述
response header已经成功添加。

Ok,我们已经完成了对Spring Cloud Gateway的配置和使用,初步了解了Spring Cloud Gateway的用法,其实使用和配置起来一点都不复杂。

Thanks!

Spring Cloud gateway - CircuitBreaker GatewayFilte

Spring Cloud gateway - CircuitBreaker GatewayFilte

前面学习Spring cloud gateway的时候,做测试的过程中我们发现,Spring Cloud Gateway不需要做多少配置就可以使用Spring Cloud LoadBalance的功能,比如:

spring:
  application:
    name: spring-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: lb://orderservice
          predicates:
            - Path=/order/*
eureka:
  client:
    service-url: # eureka service
      defaultZone: http://127.0.0.1:10086/eureka/
server:
  port: 9095

就实现了通过Eureka注册中心进行路由、并自动启用了负载均衡。

其实这个功能是通过Gateway的过滤器实现的。

我们已经知道,Spring Cloud Gateway内置n多过滤器,我们今天就学习其中两个过滤器:

  1. The CircuitBreaker GatewayFilter
  2. The ReactiveLoadBalancerClientFilter

The ReactiveLoadBalancerClientFilter

该Filter原理非常简单,就是上面说过的配置项uri中有 lb 标记,比如上例中的 lb://orderservice 。

ReactiveLoadBalancerClientFilter会查找uri配置中如果包含 lb 的话,会使用Spring Cloud ReactorLoadBalancer解析uri为实际的host和port。

所以只要在配置文件中uri指定lb标记,就会启用Spring Cloud LoadBalancer,简直就是,不要太方便。

ReactiveLoadBalancerClientFilter是Spring Cloud Gateway的全局过滤器,因此你不需要做特殊配置,自动全局生效。

The CircuitBreaker GatewayFilter

CircuitBreaker GatewayFilter是路由过滤器,所以,如果想要其生效,必须在路由下进行配置,比如:

spring:
  cloud:
    gateway:
      routes:
      - id: circuitbreaker_route
        uri: https://example.org
        filters:
        - CircuitBreaker=myCircuitBreaker

断路器基础

我们前面学习过Hystrix,了解了断路器的作用以及基本原理,知道断路开关有闭合、打开、半开半闭三个状态,以下是Hystrix的断路开关状态描述:

  1. 闭合:默认为闭合状态,可以对服务正常调用。
  2. 打开:服务调用失败达到设定的阈值后打开,一定时间范围(MTTR 平均故障处理时间)内不会调用服务。打开时长达到MTTR设置的时间后,切换到半熔断状态(半开半闭)。
  3. 半开半闭:半熔断状态,此状态下允许请求访问服务一次,如果访问成功则关闭断路器,否则再次打开断路器。

不同的断路器实现都会遵循在以上三个状态下工作的基础原理,只不过开关打开条件、半开半闭状态下变更为开、闭状态的条件可能会有所不同。

CircuitBreaker GatewayFilter

我们今天要学习的是Spring Cloud Gateway的断路过滤器,而不是Spring Cloud CircuitBreaker。

关于CircuitBreaker GatewayFilter,官网描述:

The Spring Cloud CircuitBreaker GatewayFilter factory uses the Spring Cloud CircuitBreaker APIs to wrap Gateway routes in a circuit breaker. Spring Cloud CircuitBreaker supports multiple libraries that can be used with Spring Cloud Gateway. Spring Cloud supports Resilience4J out of the box.

CircuitBreaker GatewayFilter工厂采用Spring Cloud断路器的接口将网关路由包装在Spring Cloud断路器中。Spring Cloud CircuitBreaker 支持众多可用于Spring Cloud网关的库。其中Resilience4J 对于Spring Cloud来说是开箱即用的。

意思除了Resilience4J 之外,Spring Cloud还应该支持其他类型的断路器。但是具体还有哪些,官网并没有说。

Spring Cloud CircuitBreaker

Spring Cloud CircuitBreaker 我们后面会专门进行学习研究,今天的主要目标是Spring Cloud Gateway的CircuitBreaker GatewayFilter。不过既然CircuitBreaker GatewayFilter 官网说Spring Cloud CircuitBreaker支持多个断路器,那我们就大概看一下Spring Cloud CircuitBreaker,简单了解一下官网所说的Spring Cloud CircuitBreaker支持多个断路器的libraries具体是什么意思。

还是看官网,找到Spring Cloud CircuitBreaker的官网介绍:

在这里插入图片描述
Spring Cloud CircuitBreaker提供了一个对不同断路器实现的抽象,为应用提供了一组API,使得你(猿类们啊...)可以在自己应用中轻松选择适合你自己应用的断路器实现。

支持的断路器实现包括:

  1. Resilience4J
  2. Sentinel
  3. Spring Retry

官网文档并没有提到Hystrix,Hystrix是属于Netflix的组件,并不属于Spring Cloud CircuitBreaker,所以Spring有了自己的断路器,Hystrix就会被他主动抛弃(并不是说不支持了,只不过是,不亲了啊...)。

所以,概念梳理清楚了,Spring Cloud CircuitBreaker是一个对各断路器实现的抽象,可以灵活支持Resilience4J、Sentinel以及Spring Retry。而CircuitBreaker GatewayFilter 是Spring Cloud网关的一个断路器过滤器,该过滤器内部封装了Spring Cloud CircuitBreaker,可以支持Spring Cloud CircuitBreaker的各实现库包括Resilience4J、Sentinel及Spring Retry。

CircuitBreaker GatewayFilter官网提到Resilience4J是开箱即用的,所以,Resilience4J应该是CircuitBreaker GatewayFilter中断路器的默认实现。

CircuitBreaker GatewayFilter 应用

模块gateway的pom文件中引入Resilience4J:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springCloud</artifactId>
        <groupId>com.example</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springgateway</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

</project>

模块gateway的配置文件

spring:
  application:
    name: spring-gateway
  cloud:
    gateway:
      routes:
        - id: path_route
#          uri: http://127.0.0.1:9090
          uri: lb://orderservice
          predicates:
            - Path=/order/*
          filters:
            - name: My
              args:
                name: My own pre-filter
            - name: CircuitBreaker
              args:
                name: myCircuitBreaker
                fallbackUri: forward:/fallback
                statusCodes: 500
        - id: orderfallback_route
          uri: lb://orderservice
          predicates:
            - Path=/fallback
eureka:
  client:
    service-url: # eureka service
      defaultZone: http://127.0.0.1:10086/eureka/
server:
  port: 9095

增加CircuitBreaker的配置,调用发生错误的话、或者返回的status code是500的话,则出发fallback。

fallback也可以通过路由配置到指定位置,比如我们案例中指向orderservice的fallback路径。

orderservice模块增加fallback请求的相应

增加一个controller:

package com.example.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class FallbackController {
    @GetMapping("/fallback")
    public String fallback(){
        return "this is fallback from orderservice...";
    }
}

orderservice模块增加一个失败请求

修改orderservice,模拟一个失败请求,以及一个返回500的请求,以便测试:

    @GetMapping("/orderCount")
    public String orderCount(@RequestParam int count, HttpServletRequest request, HttpServletResponse response){
        log.info("Come here to get Order....123===");
        if(count==500 || count==404){
            response.setStatus(count);
        }

        return "10/count:"+10/count+" from:"+serverPort;
    }

增加一个orderCount方法,判断请求参数后做返回,返回信息中包含了一个除法运算 10/count,这样我们请求参数count如果是500的话,会返回status code 500,请求参数count如果是0的话,将会触发服务端的 / by zero异常。

测试

启动Eureak模块、gateway模块、以及orderservice模块。

在这里插入图片描述
前端访问,首先送入count=0,触发服务端除零错误后,路由的fallback:
在这里插入图片描述
然后传入count=500,触发gateway的statusCode=500的fallback路由:
在这里插入图片描述
最后送入一个正常的count=1的值,获取到正常的返回:
在这里插入图片描述
OK,Spring Cloud gateway的CircuitBreaker GatewayFilte就到这里了,源码没有研究,还有,Spring Cloud的CircuitBreaker 也没有深入研究,下次。

Spring Cloud gateway 三 自定义过滤器 GatewayFilter

Spring Cloud gateway 三 自定义过滤器 GatewayFilter

之前 zuul 网关介绍。他有过滤器周期是四种,也是四种类型的过滤器。而 gateway 只有俩种过滤器:“pre” 和 “post”。

  • PRE: 这种过滤器在请求被路由之前调用。
  • POST:这种过滤器在路由到微服务以后执行。

这俩种过滤器是不是很熟悉。其实和 zuul 的过滤器很像。

但是 gateway 过滤器又可以分为俩种。GatewayFilter 与 GlobalFilter。

  • GlobalFilter 全局过滤器
  • GatewayFilter 将应用到单个路由或者一个分组的路由上。

还有内置的过滤器断言机制。在上一篇已经做过介绍。本篇就不在介绍。

同样全局过滤器也在上一篇列举了全局过滤器的一种写法,有兴趣的同学可以回过头看一下。

自定义过滤器

创建 ServerGatewayFilter 类

package com.xian.cloud.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * <Description>
 *
 * @author xianliru@100tal.com
 * @version 1.0
 * @createDate 2019/11/07 17:34
 */
@Slf4j
public class ServerGatewayFilter implements GatewayFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("ServerGatewayFilter filter ");
        return chain.filter( exchange );
    }
    @Override
    public int getOrder() {
        return 0;
    }
}

创建 GatewayRoutesConfiguration

package com.xian.cloud.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * <Description>
 *
 * @author xianliru@100tal.com
 * @version 1.0
 * @createDate 2019/11/08 09:45
 */
@Configuration
@Slf4j
public class GatewayRoutesConfiguration {
    /**
     * java 配置 server 服务路由
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder) {
        log.info("ServerGatewayFilter filtet........");
        return builder.routes()
                .route(r ->
                        r.path("/server/**")
                                .filters(
                                        f -> f.stripPrefix(1)
                                                .filters(new ServerGatewayFilter())
                                )
                                .uri("lb://cloud-discovery-server")
                )
                .build();
    }
}

启动服务 gateway 服务日志打印

[2019-11-08 11:07:17.357] [] [] [] [] [INFO ] com.xian.cloud.filter.GatewayRoutesConfiguration - ServerGatewayFilter filtet........

命令行 curl http://localhost:9000/server/server/hello?name=tom 返回 hello tom age = 20

日志打印

[2019-11-08 11:08:09.966] [] [] [] [] [INFO ] com.xian.cloud.filter.AuthorizeFilter - AuthorizeFilter token 全局过滤器 token:null,uid:null
[2019-11-08 11:08:09.970] [] [] [] [] [INFO ] com.xian.cloud.filter.ServerGatewayFilter - ServerGatewayFilter filter 

我们看到日志已经打印我们想看到的日志。

优先级

java 配置方式与 yml 文件配置。java 配置优先级更高。亲测

整理 断言 和 自定义过滤器

  • 断言 其实断言的作用是不是要将请求路由到服务上,是不是符合条件。就像玩过山车危险游戏一样,会有年龄,体重、病史的一些限制。
  • 过滤器 就还是过山车的案例,你符合了条件。那么好,我要给你带上安全带等一些安全保护措施,才能让你真正的玩耍。道理是相同的。

gateway 的断言和过滤器提供如此丰富的内置断言和过滤器。让我们有非常丰富的组合模式,应对我们实际开发的场景。还可以根据具体的场景做一些特殊处理。

2.2.X 版本 gateway 增加了类似于注册中心的元数据。在 gateway 配置一下元数据。带着数据请求到下游服务。有兴趣的同学可以去官网查看官方文档。

如何喜欢可以关注分享本公众号。 file

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。转载请附带公众号二维码

关于Spring Cloud Gatewayspringcloudgateway负载均衡的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于Fizz Gateway基准测试性能超越Spring Cloud Gateway、Spring cloud - gateway、Spring Cloud gateway - CircuitBreaker GatewayFilte、Spring Cloud gateway 三 自定义过滤器 GatewayFilter的相关知识,请在本站寻找。

本文标签: