Spring Cloud Framework Learning-Spring Cloud Gateway

1 Introduction

A complete microservice architecture consists of a series of independently running microservices. Each microservice is responsible for completing different business functions. This requires the API gateway to uniformly manage the interfaces provided by the microservices. The main functions of the API gateway are as follows:

  • Request access: manage all access requests and serve as the request entry for all microservice API interfaces
  • Current limiting: flow control, staggered peak flow control, can define a variety of current limiting rules
  • Security management: authority identity authentication, desensitization, traffic cleaning, back-end signature (to ensure full-link trusted calls) inspection, blacklist restrictions (restrictions on illegal calls)
  • Unified management: Provide unified monitoring tools (record request response data, API time-consuming analysis, performance monitoring), unified logging, unified configuration management tools, Swagger tools, etc.

Spring Cloud Gateway is an API gateway service built on top of the Spring ecosystem, based on technologies such as Spring 5, Spring Boot 2 and Project Reactor. Gateway aims to provide a simple and effective way to route APIs, and provide some powerful filter functions, such as circuit breaking, current limiting, retrying, etc.

Spring Cloud Gateway has the following features:

  • Built on Spring Framework 5, Project Reactor and Spring Boot 2.0;
  • Dynamic routing: able to match any request attribute;
  • Predicate (assertion) and Filter (filter) can be specified for routing;
  • Integrate the circuit breaker function of Hystrix;
  • Integrate Spring Cloud service discovery function;
  • Easy to write Predicate (assertion) and Filter (filter);
  • Request current limiting function;
  • Path rewriting is supported.

Three important concepts of Spring Cloud Gateway:

  • Route (routing): routing is the basic module of building a gateway, itConsists of ID, target URI, a series of assertions and filters, match the route if the assertion is true;
  • Predicate: Refers to Java 8's Function Predicate. The input type is ServerWebExchange in Spring Framework. This allows developers to match anything in an HTTP request, such as request headers or request parameters. Routing if the request matches the assertion;
  • Filter (filter): refers to the instance of GatewayFilter in the Spring framework. Using the filter, the request can be modified before and after the request is routed.

Example diagram of the working principle of Spring Cloud Gateway:
insert image description here
The client sends a request to Spring Cloud Gateway. If the request matches the route defined by the gateway program, the request will be sent to the gateway Web handler, and the handler runs a specific request filter. chain.

The reason the filters are separated by a dashed line is that the filter may execute logic before and after sending the proxy request. All pre filter logic is executed first, and then the proxy request is executed; after the proxy request is completed, the post filter logic is executed.

Comparison with Zuul:

  1. Zuul is an open source project of Netflix, and Spring Cloud Gateway is a product in the Spring family, which can be better integrated with other components in the Spring family.
  2. Zuul 1.x uses a blocking architecture based on Servlet 2.5. It uses a blocking API and does not support long connections, such as Websocket.
  3. Spring Cloud Gateway supports throttling.
  4. Spring Cloud Gateway is developed based on Netty, realizes asynchronous and non-blocking, occupies less resources, and has better performance than Zuul.

2. Basic Usage

Spring Cloud Gateway supports two different ways to configure routing: encoded and yml file configuration

2.1 Coded configuration routing

Create a Spring Boot project and add Spring Cloud Gateway dependencies:

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-hateoas</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

After the project is created, request forwarding is realized by configuring RouteLocator

@SpringBootApplication
public class DemoApplication {
    
    

	public static void main(String[] args) {
    
    
		SpringApplication.run(DemoApplication.class, args);
	}

	@Bean
    RouteLocator routeLocator(RouteLocatorBuilder builder){
    
    
        return  builder.routes().route("test_route", r -> r.path("/get").uri("http://httpbin.org")).build();
    }
}

After the configuration is complete, restart the project and request http://localhost:8080/get

insert image description here

2.2 Configuration file configuration routing

Corresponding properties configuration example

spring.cloud.gateway.routes[0].id=test_route
spring.cloud.gateway.routes[0].uri=http://httpbin.org
spring.cloud.gateway.routes[0].predicates[0]=Path=/get

Corresponding YML configuration example

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
        uri: http://httpbin.org
        predicates:
          - Path=/get

2.3 Service configuration

Add dependencies to the Gateway project and register Gateway to Eureka.

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

Add registry configuration to the configuration file and enable automatic proxy

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Path=/get
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能
#         lower-case-service-id:true#使用小写服务名,默认是大写
  application:
    name: gateway
eureka:
  client:
    service-url:
      defaultZone: http://localhost:1111/eureka
logging:
  level:
    org.springframework.cloud.gateway: debug
在这里插入代码片

Start the Eureka service, start the Gateway and provider (service provider) services, and register the Gateway and provider services to the Eureka registry.
insert image description here
The port number of the provider service is 1113, and the port of the Gateway is 8080. Next, access the hello interface of the provider service through the Gateway

insert image description here

3. Predicate Affirmations

Spring Cloud Gateway uses route matching as part of the Spring WebFlux HandlerMapping infrastructure. Spring Cloud Gateway includes many built-in Route Predicate factories (including time matching, request method matching, request path matching, parameter matching, etc.). All of these Predicates match different attributes of the HTTP request. Multiple Route Predicate factories can be combined. Let's introduce some commonly used Route Predicates.

3.1 Time matching

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - After=2021-01-01T01:01:01+08:00[Asia/Shanghai]

Indicates that the request time will be routed after the time of 2021-01-01T01:01:01+08:00[Asia/Shanghai].

In addition to After, there are two keywords:

  • Before, indicating that the request before a certain point in time matches the route
  • Between, indicating that requests between two time points match the route, and the two time points are separated by ,

3.2 Request method matching

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Method=GET

The configuration indicates that only GET requests are routed

3.3 Request path matching

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Path=/2019/0612/{
    
    segment}

Indicates that the path satisfies the rule of /2019/0612/ and will be forwarded

3.4 Parameter matching

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Query=name

Indicates that there must be a name parameter in the request before it can be forwarded, otherwise it will not be forwarded, and parameters and parameter values ​​can also be specified.

For example, the key of the parameter is name, and the value must start with java:

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Query=name,java.*

The above multiple matching methods can also be used in combination

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Query=name,java.*
            - Path=/2019/0612/{
    
    segment}
            - Method=GET

3.5 Cookie matching

Requests with the specified cookie will match this route.

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Cookie=username

3.6 Request Header Matching

Requests with the specified cookie will match this route. The following request with the request header "X-Request-Id:test123" can match this route.

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Header=X-Request-Id

3.7 Host host matching

Requests with the specified Host will match this route. The following request with Host:www.baidu.com will match this route

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - Host=www.**.com

3.8 Remote Address RemoteAddr Matching

Requests initiated from the specified remote address can match this route.

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: http://httpbin.org
          predicates:
            - RemoteAddr=192.168.1.1/24

3.8 Weight matching

Use weights to route corresponding requests. The following indicates that 80% of requests will be routed to localhost:8201, and 20% will be routed to localhost:8202.

spring:
  cloud:
    gateway:
      routes:
      - id:weight_high
        uri:http://localhost:8201
        predicates:
        - Weight=group1,8
      - id: weight_low
        uri: http://localhost:8202
        predicates:
        - Weight=group1,2

4. Filter filter

Filters in Spring Cloud Gateway are divided into two categories: global filter GlobalFilter and gateway filter GatewayFilter.

The global filter GlobalFilter implements the GlobalFilter interface. Spring Cloud Gateway provides the following implementation classes by default.
insert image description here

insert image description here

A detailed introduction to the global filter GlobalFilter: GlobalFilter of spring-cloud-gateway

Gateway filter GatewayFilter implements the GatewayFilter interface. Spring Cloud Gateway provides the following implementation classes by default.
insert image description here

insert image description here
The following introduces several commonly used gateway filters GatewayFilter.

4.1 AddRequestParameter GatewayFilter

Use the AddRequestParameter filter to automatically add additional parameters to the /test_get request

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: lb://provider
          filters:
            - AddRequestParameter=name,robot
          predicates:
            - Path=/test_get

uri: lb://provider is used to enable the load balancing function, and the provider service provides the interface /test_get

insert image description here
The browser requests the Gateway, implements the test_get interface forwarded to the provider, and automatically adds parameters.
insert image description here
Request the test_get interface, if there are already parameters, additional parameters for filter configuration will be added.
insert image description here

4.2 StripPrefix GatewayFilter

StripPrefix GatewayFilter is a filter that removes the specified number of path prefixes.

spring:
  cloud:
    gateway:
      routes:
      - id: test_route
        uri: http://localhost:8201
        predicates:
        - Path=/user-service/**
        filters:
        - StripPrefix=2

The StripPrefix=2 configuration will remove two bits from the path of the request starting with /user-service/, that is, the request

http://localhost:9201/user-service/a/user/1

Equivalent to requesting this address:

http://localhost:8201/user/1

4.3 PrefixPath GatewayFilter

PrefixPath GatewayFilter adds filters to the original path.

spring:
  cloud:
    gateway:
      routes:
      - id: test_route
        uri: http://localhost:8201
        predicates:
        - Path=/user-service/**
        filters:
        - PrefixPath=/user

Configure the request with the prefix of /user-service/ to add the /user path prefix, that is, the request

http://localhost:9201/user-service/1

Equivalent to requesting this address:

http://localhost:8201/user-service/user/1

4.4 Hystrix GatewayFilter

Hystrix filters allow us to add circuit breaker functionality to gateway routes, making services immune to cascading failures and providing service degradation handling.

First add Hystrix-related dependencies in pom.xml and enable the circuit breaker function

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

Add a processing class for related service degradation

@RestController
public class FallbackController {
    
    


    @GetMapping("/fallback")
    public Object fallback() {
    
    
        Map<String,Object> result = new HashMap<>();
        result.put("data",null);
        result.put("message","get request fallback!");
        result.put("code",500);
        return result;
    }
}

Add related configurations in the configuration file: when a routing error occurs, it will be forwarded to the controller for service degradation processing.

spring:
  cloud:
    gateway:
      routes:
        - id: hystrix_route
          uri: http://localhost:8201
          predicates:
            - Method=GET
          filters:
            - name: Hystrix
              args:
                name: fallback
                fallbackUri: forward:/fallback

The request http://localhost:8080/1 found that the processing information of service degradation has been returned, because http://localhost:8201/ does not provide this interface.
insert image description here

4.5 RequestRateLimiter GatewayFilter

The RequestRateLimiter filter can be used for current limiting. Use the RateLimiter implementation to determine whether the current request is allowed to continue. If the request is too frequent, it will return the HTTP 429 - Too Many Requests response by default.

Add related dependencies in pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

Add the configuration class of the current limiting policy, and provide the policy ipKeyResolver to limit the current based on the access IP.

@Configuration
public class RedisRateLimiterConfig {
    
    

    @Bean
    public KeyResolver ipKeyResolver() {
    
    
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
}

Add the configuration of Redis and RequestRateLimiter in the yml configuration file. The configuration here restricts the flow of all GET requests by IP.

spring:
  redis:
    host: localhost
    password: 123
    port: 6379
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: lb://provider
          filters:
            - AddRequestParameter=name,robot
          predicates:
            - Path=/test_get
        - id: hystrix_route
          uri: http://localhost:8201
          predicates:
            - Method=GET
          filters:
            - name: Hystrix
              args:
                name: fallbackcmd
                fallbackUri: forward:/fallback
        - id: requestratelimiter_route
          uri: http://localhost:1113
          predicates:
            - Method=GET
          filters:
            - name: RequestRateLimiter
              args:
                #每秒允许处理的请求数量
                redis-rate-limiter.replenishRate: 1
                #每秒最大处理的请求数量
                redis-rate-limiter.burstCapacity: 2
                #限流策略,对应策略的Bean
                key-resolver: "#{@ipKeyResolver}"

      discovery:
        locator:
          enabled: true # 开启自动代理
  application:
    name: gateway
eureka:
  client:
    service-url:
      defaultZone: http://localhost:1111/eureka
logging:
  level:
    org.springframework.cloud.gateway: debug

The algorithm used by RequestRateLimiter is the token bucket algorithm, and the token bucket algorithm is introduced

token bucket algorithm

Configuration instructions for RequestRateLimiter:

  • The filter name must be "RequestRateLimiter"
  • redis-rate-limiter.replenishRate: How many requests per second the user is allowed to process. This is the filling rate of the token bucket.
  • redis-rate-limiter.burstCapacity: The capacity of the token bucket, allowing the maximum number of requests to be completed within one second. This is the number of tokens the token bucket can hold.
  • redis-rate-limiter.requestedTokens: is how many tokens each request consumes, the default is 1.
  • key-resolver: References beans by name using SpEL expressions.

The next test is to start the provider service, register to the registration center http://localhost:1111/eureka, and provide the hello interface. Frequent browser visits: http://localhost:8080/hello will return an error with a status code of 429;
insert image description here
check the Key in Redis:
insert image description here

  • The curly brackets are the current limiting Key. Here we are testing the ip current limiting, so the key is the IP, and the local access is 0:0:0:0:0:0:0:1/

  • timestamp: stores the number of seconds of the current time, that is, System.currentTimeMillis() / 1000 or Instant.now().getEpochSecond()
    insert image description here

  • tokens: stores the corresponding number of available tokens in the current second
    insert image description here

We can not only limit the current through ip, but also limit the current according to other parameters of ServerHttpRequest
insert image description here

For example, limit the flow based on the username in the request parameter

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

4.6 Retry GatewayFilter

Retry GatewayFilter Factory is a request retry filter. When the backend service is unavailable, the gateway will initiate a retry request according to the configuration parameters. Retry GatewayFilter supports configuration of the following parameters:

  • retries: the number of retries, the default value is 3
  • statuses: HTTP Status Codes that should be retried, refer to org.springframework.http.HttpStatus, multiple status codes can be configured here.
  • methods: HTTP Methods that should be retried, reference org.springframework.http.HttpMethod, default is GET.
  • series: The series of Status Codes that should be retried. For reference org.springframework.http.HttpStatus.Series, the default value is SERVER_ERROR(5), which means that all status codes in the 5xx segment will initiate a retry. If the series is configured with an error code segment, but the status is not configured, it will still match the series for retry.
  • exceptions: the list of exceptions that should be retried, the default value is IOException and TimeoutException
  • backoff: Configure exponential backoff for retries. The calculation formula of the retry interval is firstBackoff * (factor ^ n), n is the number of retries; if maxBackoff is set, the maximum backoff limit is maxBackoff. If basedOnPreviousValue is set to true, the backoff calculation formula is prevBackoff * factor. The default value is disabled and not enabled.

Modify the configuration file to implement one retry when the Get request returns a 500 response code.

spring:
  redis:
    host: localhost
    password: 123
    port: 6379
  cloud:
    gateway:
      routes:
        - id: retry_route
          uri: http://localhost:1113
          predicates:
          - Method=GET
          filters:
            - name: Retry
              args:
                #需要进行重试的次数
                retries: 1
                #返回状态码为500进行重试
                statuses: INTERNAL_SERVER_ERROR
                backoff:
                  firstBackoff: 10ms
                  maxBackoff: 50ms
                  factor: 2
                  basedOnPreviousValue: false      
      discovery:
        locator:
          enabled: true # 开启自动代理
  application:
    name: gateway
eureka:
  client:
    service-url:
      defaultZone: http://localhost:1111/eureka
logging:
  level:
    org.springframework.cloud.gateway: debug

Browser access http://localhost:8080/hello.
insert image description here
Check the log print of the http://localhost:1113 service that is called in the background, and you can see that two errors have been reported. Indicates a retry was made.
insert image description here

4.7 Custom Global Filters

Implement custom GlobalFilter and Ordered interfaces to define global filters. The DEMO example of the official document:

@Bean
public GlobalFilter customFilter() {
    
    
    return new CustomGlobalFilter();
}

public class CustomGlobalFilter implements GlobalFilter, Ordered {
    
    

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    
        log.info("custom global filter");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
    
    
        return -1;
    }
}

Code example for implementing a global authentication filter:

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    
    

    private static final String AUTH_CHECK_PATH="/api/**/auth/**";
    private static final String LOGIN_REQUEST="请您先登录再访问!";
    private static final String SESSION_EXPIRED="当前会话已过期,请重新登录!";


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();

        AntPathMatcher antPathMatcher = new AntPathMatcher();
        if (antPathMatcher.match(AUTH_CHECK_PATH,path)){
    
    
            List<String> tokenList = request.getHeaders().get("token");
            //没有token,直接响应失败
            if (tokenList==null){
    
    
                ServerHttpResponse response = exchange.getResponse();
                return out(response,LOGIN_REQUEST);
            }
            //token校验失败,直接响应失败
            boolean isCorrectToken = JwtHelper.checkJwtTToken(tokenList.get(0));
            if (!isCorrectToken){
    
    
                ServerHttpResponse response = exchange.getResponse();
                return out(response,SESSION_EXPIRED);
            }

        }
        //放行
        return chain.filter(exchange);
    }

    /**
     * 定义过滤器的优先级,值越小,优先级越高
     * @return
     */
    @Override
    public int getOrder() {
    
    
        return 0;
    }


    private Mono<Void> out(ServerHttpResponse response,String prompt) {
    
    
        JsonObject message = new JsonObject();
        message.addProperty("success", false);
        message.addProperty("code", 28004);
        message.addProperty("data", "");
        message.addProperty("message", prompt);
        byte[] bytes = message.toString().getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bytes);
        //指定编码,否则在浏览器中会中文乱码
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        //输出http响应
        return response.writeWith(Mono.just(buffer));
    }
}

References:
1. Spring Cloud Gateway Official Documentation
2. Spring Cloud Gateway: New Generation API Gateway Service

Guess you like

Origin blog.csdn.net/huangjhai/article/details/124544629