5, Microservice gateway (to be modified)

What I wrote earlier: most of this article (all of it is OK) is copied, and the materials in the classroom are very good. I feel ashamed of writing, but if I don't write it, it will affect the content of the whole blog. I'll revise / write my notes later.
Thank you for passing by. I hope the student's notes can give you a trivial reference (2 / 100)
Java basic thought map, a link to the complete Java System
Some content links of microservices. Thank you. Let's start.
About a dozen articles

5.1 introduction to microservice gateway

In Chapter 3, we introduced the call and load balancing between microservices through Spring Cloud LoadBalancer, and the use of Spring Cloud OpenFeign declarative call. How can our various microservices be provided to external application calls?
Of course, because it is a REST API interface, there is no problem for external clients to directly call various microservices. But for various reasons, this is not a good choice. Let the client directly communicate with each micro service, there will be the following problems.
● the client will request different micro services many times, which increases the complexity of the client.
● there are cross domain requests, and the processing will become relatively complex in certain scenarios.
● the implementation of authentication is complex, and each micro service needs independent authentication.
● it is difficult to reconstruct, and the project iteration may lead to the re division of micro services. If the client communicates directly with the microservice, the refactoring will be difficult to implement.
● if some micro services use firewall and browser unfriendly protocols, direct access will be difficult.
Facing the above problems, how should we solve them? The answer is: service gateway! In microservice system, microservice resources are generally not directly exposed to external clients. The advantage of this is to hide internal services to solve the above problems.
Gateway has many important meanings, which are embodied in the following aspects.
● the gateway can do some identity authentication, authority management, prevent illegal request operation services, etc., and play a certain role in protecting the services.
● the gateway manages all micro services in a unified way and exposes them to the outside world. The external system does not need to know the complexity of the mutual call of the micro services architecture. At the same time, it also avoids the leakage of some sensitive information of the internal services.
● easy to monitor. The monitoring data can be collected at the microservice gateway and pushed to the external system for analysis.
&   nbsp; ● the client only deals with the service gateway, which reduces the number of interactions between the client and various micro services.
● multi channel support, which can provide different API service gateways according to different clients (WEB end, mobile end, desktop end...).
● gateway can be used for traffic monitoring. Under the condition of high parallel delivery, the service flow is limited and degraded.
● the gateway separates the service from the inside to facilitate testing.
Microservice gateway can realize routing, load balancing and other functions. Similar to Nginx, the function of reverse proxy. In microservice architecture, back-end services are often not directly open to the caller, but routed to the corresponding services through an API gateway according to the requested URL. When the API gateway is added, a wall is created between the third-party caller and the service provider to control the permission in the API gateway. At the same time, the API gateway sends the request to the back-end service in the way of load balancing. The architecture of microservice gateway is shown in Figure 5-1.

5.2 introduction to spring cloud gateway

5.2.1 introduction

Spring Cloud gateway is a new project of Spring Cloud. The project is a gateway developed based on Spring 5.0, Spring Boot 2.0 and Project Reactor. It aims to provide a simple and effective unified API routing management method for microservice architecture.
As a gateway in the Spring Cloud ecosystem, the goal of Spring Cloud Gateway is to replace Zuul. In Spring Cloud versions above 2.0, the latest performance versions above Zuul 2.0 are not integrated, and the old version of non Reactor mode before Zuul 2.0 is still used. In order to improve the performance of the gateway, the Spring Cloud Gateway is implemented based on the WebFlux framework, and the bottom layer of the WebFlux framework uses the high-performance Reactor mode communication framework Netty. The goal of Spring Cloud Gateway is not only to provide a unified routing method, but also to provide the basic functions of the gateway based on the Filter chain, such as security, monitoring / indicators, and current limiting.
Note: nety, a high-performance communication framework, is used at the bottom of Spring Cloud Gateway.

5.2.2 characteristics

The official of spring cloud introduces the features of spring cloud gateway as follows:
● based on Spring Framework 5, Project Reactor and Spring Boot 2.0
● integrated Spring Cloud DiscoveryClient
● predictions and Filters act on specific routes and are easy to write
● it has advanced functions of some gateways: dynamic routing, current limiting and path rewriting
● integrated Spring Cloud DiscoveryClient
● integrated fuse CircuitBreaker
From the above characteristics, it is not different from Zuul's characteristics. The main difference between spring cloud gateway and Zuul lies in the underlying communication framework.
Briefly explain the three terms above:
(1) Filter:
Similar to Zuul's filter in concept, it can be used to intercept and modify requests and secondary process downstream responses. The filter is org springframework. cloud. gateway. filter. An instance of the gatewayfilter class.
(2) Route:
The basic composition module of gateway configuration is similar to Zuul's routing configuration module. A Route module is defined by an ID, a target URI, a set of assertions and a set of filters. If the assertion is true, the Route matches and the destination URI is accessed.
(3) Predicate:
This is a Java 8 Predicate that can be used to match any content from an HTTP request, such as headers or parameters. The input type of the assertion is a ServerWebExchange.

5.2.3 introduction cases

Create microservice Gateway project 05_cloud_gateway.
1. Add dependency
Add Eureka Discovery Client and Spring Cloud Gateway, as shown in Figure 5-2.

pom. The complete XML code is as follows.

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.9</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lxs.demo</groupId>
    <artifactId>05_cloud_gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>05_cloud_gateway</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.3</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </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>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2. Starter

package com.lxs.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {

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

}

3. Configuration file

application.yml The code is as follows.
server:
  port: 9005
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: url-proxy-1
          uri: https://blog.csdn.net
          predicates:
            - Path=/csdn      
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:9004/eureka

4. Start and test
Start Eureka Server and gateway microservice access http://localhost:9005/csdn , found route to https://blog.csdn.net

5.2.4 treatment process

The client sends a request to the Spring Cloud Gateway. Then find the route matching the request in the Gateway Handler Mapping and send it to the Gateway Web Handler. The Handler then sends the request to our actual service through the specified filter chain, executes the business logic, and then returns. The filters are separated by dashed lines because the filter may execute business logic before ("pre") or after ("post") sending the proxy request. As shown in Figure 5-3.

5.3 route configuration mode

Routing is the basic component module of gateway configuration, which is similar to Zuul's routing configuration module. A Route module is defined by an ID, a target URI, a set of assertions and a set of filters. If the assertion is true, the Route matches and the destination URI is accessed.

5.3.1 basic route configuration mode

If the requested destination address is a single URI resource path, the configuration file example is as follows.

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: service1
          uri: https://blog.csdn.net
          predicates:
            - Path=/csdn

The meaning of each field is as follows.
● ID: our customized routing ID, which remains unique
● uri: target service address
● predictions: routing conditions. Predictions accept an input parameter and return a boolean result. The interface contains a variety of default methods to combine predict into other complex logic (such as and, or, not).
The above configuration means that a URI proxy rule with id url-proxy-1 is configured, and the routing rule is when accessing the address http://localhost:8080/csdn/1.jsp When, it will be routed to the upstream address https://blog.csdn.net/1.jsp .

5.3.2 code based routing configuration

The forwarding function can also be realized through code. We can add the method customRouteLocator() in the startup class GateWayApplication to customize the forwarding rules.

@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {

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

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("path_route", r -> r.path("/csdn")
                        .uri("https://blog.csdn.net"))
                .build();
    }
}

5.3.3 route configuration mode combined with registration center

The schema protocol part of uri is a custom lb: type, which means subscribing services from the micro Service Registry (such as Eureka) and routing services through load balancing. The code is as follows.

server:
  port: 9005
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: service1
          uri: https://blog.csdn.net
          predicates:
            - Path=/csdn
        - id: service2
        # uri: http://127.0.0.1:9001
          uri: lb://cloud-payment-service
          predicates:
            - Path=/payment/**
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:9004/eureka

The routing configuration mode combined with the registry is actually very different from that of a single URI, only because the schema protocol of the URI is different. The schema protocol of the address of a single URI, generally http or https protocol. When you start multiple payment micro services, you will find that port 900090001 appears in turn.

5.4 route matching rules

One of the main functions of Spring Cloud Gateway is to forward requests. The definition of forwarding rules mainly includes three parts, as shown in Table 5-1.

The function of Spring Cloud Gateway is very powerful. We can see it only through the design of predictions. Previously, we just used predictions for simple condition matching. In fact, Spring Cloud Gateway has built-in many predictions functions for us.
Spring Cloud Gateway uses HandlerMapping of Spring WebFlux as the underlying support to match forwarding routes. Spring Cloud Gateway has built-in many predictions factories, which are matched through different HTTP request parameters. Multiple predictions factories can be used in combination. As shown in Figure 5-4.

5.4.1 Predicate assertion condition

Predicate comes from Java 8 and is a function introduced in Java 8. Predicate accepts an input parameter and returns a boolean result. The interface contains a variety of default methods to combine predict into other complex logic (such as and, or, not). It can be used to verify the parameters requested by the interface and judge whether there are changes in new and old data, which need to be updated. In the Spring Cloud Gateway, Spring uses the predict feature to implement various route matching rules, which are matched to the corresponding route through different conditions such as Header and request parameters. There is a figure on the Internet that summarizes the implementation of several predictions built into Spring Cloud. As shown in Figure 5-5.

To put it bluntly, predict is to implement a set of matching rules to facilitate the request to find the corresponding Route for processing. Next, let's take over the use of several built-in predictions in Spring Cloud GateWay. The forwarding rules assume that the forwarding URIs are set to http://localhost:9001 , common predict, as shown in table 5-2

1. Match through request parameters
Query Route Predicate supports passing in two parameters, one is the attribute name and the other is the attribute value. The attribute value can be a regular expression.

spring:
  cloud:
    gateway:
      routes:
        - id: service3
          uri: https://www.baidu.com
          order: 0
          predicates:
            - Query=smile

With this configuration, the route can be matched as long as the parameters of the smile attribute are included in the request. Using curl test, enter curl localhost: 9005? Smile = x & id = 2. After testing, it is found that the route will be matched as long as the request summary has smile parameters, and will not be matched without smile parameters.
You can also configure the value of Query in the form of key value pairs, so that when the request comes, the attribute value and regular will be matched, and the matching will be routed.

spring:
  cloud:
    gateway:
      routes:
        - id: service3
          uri: https://www.baidu.com
          order: 0
          predicates:
            - Query=keep, pu.

In this way, only when the request contains the keep attribute and the parameter value is a three digit string starting with pu, will it be matched and routed. Using curl test, enter curl localhost:8080?keep=pub, the test can return the page code. Change the property value of keep to pubx, and 404 will be reported when you visit again, which proves that the route needs to match the regular expression before routing.
2. Match through Header
Like Query Route Predicate, Header Route Predicate also receives two parameters: the attribute name and a regular expression in a header. If the attribute value matches the regular expression, it will be executed.

spring:
  cloud:
    gateway:
      routes:        
        - id: service4
          uri: https://www.baidu.com
          order: 0
          predicates:
            - Header=X-Request-Id, \d+

Using curl test, enter curl on the command line http://localhost:9005 -H "X-Request-Id:88", the page code is returned to prove that the matching is successful. Change the parameter - H "X-Request-Id:88" to - H "X-Request-Id:spring". When executing again, 404 is returned to prove that there is no match.
3. Match by Cookie
Cookie Route Predicate can receive two parameters, one is Cookie name and the other is regular expression. The routing rule will match by obtaining the corresponding Cookie name value and regular expression. If there is a match, the route will be executed, and if there is no match, it will not be executed.

spring:
  cloud:
    gateway:
      routes:        
        - id: service5
          uri: https://www.baidu.com
          predicates:
            - Cookie=sessionId, test

Use curl test, command line input, curl http://localhost:9005 --If the cookie "sessionId=test" is removed, the page code will be returned. If the - cookie "sessionId=test" is removed, a 404 error will be reported in the background.
4. Match through Host
Host Route Predicate receives a set of parameters and a list of matching domain names. This template is an ant separated template, which is used Number as separator. It uses the host address in the parameter as the matching rule

spring:
  cloud:
    gateway:
      routes:    
        - id: service6
          uri: https://www.baidu.com
          predicates:
            - Host=**.baidu.com      

Use curl test, command line input, curl http://localhost:9005 -H "Host: www.baidu.com" or curl http://localhost:8080 -H "Host: md.baidu.com". After testing, the above two hosts can match the host_ For route routing, if the host parameter is removed, a 404 error will be reported.
5. Match by request
You can route through different request methods such as POST, GET, PUT and DELETE.

spring:
  cloud:
    gateway:
      routes:    
        - id: service7
          uri: https://www.baidu.com
          predicates:
            - Method=PUT

Use curl test, command line input, curl -X PUT http://localhost:9005 , the test returns the page code to prove that it matches the route. In other ways, the return 404 is not found, which proves that it does not match the route
6. Path matching through request
Path RoutePredicate receives a parameter matching the path to determine whether to route.

spring:
  cloud:
    gateway:
      routes:    
        - id: service8
          uri: http://127.0.0.1:9001
          predicates:
            - Path=/payment/{segment}

If the request path meets the requirements, the route will match, curl test, command line input, curl http://localhost:9005/payment/1 ,
You can get the return value of the page normally, curl http://localhost:9005/payment2/1 , report 404, proving that the route is matched through the specified route origin.
7. Combination matching

spring:
  cloud:
    gateway:
      routes:    
        - id: service9
          uri: https://www.baidu.com
          order: 0
          predicates:
            - Host=**.foo.org
            - Path=/headers
            - Method=GET
            - Header=X-Request-Id, \d+
            - Query=foo, ba.
            - Query=baz
            - Cookie=chocolate, ch.p

When various predictions exist in the same route at the same time, the request must meet all conditions at the same time to be matched by this route.
When a request satisfies the assertion conditions of multiple routes, the request will only be forwarded by the first successfully matched route

5.4.2 filter rules

List several filters, as shown in table 5-3.

1.PrefixPath
Prefix all request paths

spring:
  cloud:
    gateway:
      routes:    
        - id: service10
          uri: http://127.0.0.1:9001
          predicates:
            - Path=/{segment}
          filters:
            - PrefixPath=/payment

Access / 123request sent to http://127.0.0.1:9001/payment/123 .
2.2. StripPrefix
Skip the specified path

spring:
  cloud:
    gateway:
      routes:    
        - id: service11
          uri: http://127.0.0.1:9001
          predicates:
            - Path=/api/{segment}
          filters:
            - StripPrefix=1
            - PrefixPath=/payment

Access at this time http://localhost:9005/api/123 Firstly, the StripPrefix filter removes a / API, and then the PrefixPath filter adds a / payment to correctly access the payment micro service.
3. RewritePath

spring:
  cloud:
    gateway:
      routes:        
        - id: service12
          uri: http://127.0.0.1:9001
          predicates:
            - Path=/api/payment/**
          filters:
            - RewritePath=/api/(?<segment>.*), /$\{segment}

Request http://localhost:9005/api/payment/123 Path, RewritePath filter rewrites the path to http://localhost:9005/payment/123 , be able to correctly access payment micro services.
4. SetPath
SetPath is similar to Rewrite with the following code.

spring:
  cloud:
    gateway:
      routes:           
        - id: service13
          uri: http://127.0.0.1:9001
          predicates:
            - Path=/api/payment/{segment}
          filters:
            - SetPath=/payment/{segment}

Request http://localhost:9005/api/payment/123 Path, SetPath filter sets the path to http://localhost:9005/payment/123 , be able to correctly access payment micro services.
5. RemoveRequestHeader
Remove a request header.

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

Remove the request header X-Request-Foo
6.RemoveResponseHeader
Remove a receipt header

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

7.SetRequestHeader
Set request header information

spring:
  cloud:
    gateway:
      routes:
        - id: setrequestheader_route
          uri: https://example.org
          filters:
          - SetRequestHeader=X-Request-Red, Blue

8.default-filters
Add filters to all requests.

spring:
  cloud:
    gateway:
      routes:        
        - id: service14
          uri: http://127.0.0.1:9001
          predicates:
            - Path=/9001/{segment}
        - id: service15
          uri: http://127.0.0.1:9000
          predicates:
            - Path=/9000/{segment}
      default-filters:
      	- StripPrefix=1
        - PrefixPath=/payment

5.5 custom filters

5.5.1 filter execution sequence

Spring cloud gateway is based on filter implementation. Similar to zuul, it has pre and post filters, which deal with pre logic and post logic respectively. The client's request first passes through the pre type filter, and then forwards the request to the specific business service. After receiving the response from the business service, it is processed by the post type filter, and finally returns the response to the client. The filter execution process is as follows. The higher the order, the lower the priority, as shown in Figure 5-6.

Filters are divided into global filters and local filters.
● global filter: effective for all routes.
● local filter: effective for the specified route.

5.5.2 global filter

Implement GlobalFilter and Ordered, rewrite relevant methods and add them to spring container management. There is no need to configure. The global filter is effective for all routes. The code is as follows.

//@Configuration
public class FilterConfig
{

    @Bean
    public GlobalFilter a()
    {
        return new AFilter();
    }

    @Bean
    public GlobalFilter b()
    {
        return new BFilter();
    }

    @Bean
    public GlobalFilter c()
    {
        return new CFilter();
    }

    @Bean
    public GlobalFilter myAuthFilter()
    {
        return new MyAuthFilter();
    }


    @Slf4j
    static class AFilter implements GlobalFilter, Ordered
    {

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            log.info("AFilter Pre logic");
            return chain.filter(exchange).then(Mono.fromRunnable(() ->
            {
                log.info("AFilter Post logic");
            }));
        }

        //   The lower the value, the higher the priority
        @Override
        public int getOrder()
        {
            return HIGHEST_PRECEDENCE + 100;
        }
    }

    @Slf4j
    static class BFilter implements GlobalFilter, Ordered
    {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            log.info("BFilter Pre logic");
            return chain.filter(exchange).then(Mono.fromRunnable(() ->
            {
                log.info("BFilter Post logic");
            }));
        }

        @Override
        public int getOrder()
        {
            return HIGHEST_PRECEDENCE + 200;
        }
    }

    @Slf4j
    static class CFilter implements GlobalFilter, Ordered
    {

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            log.info("CFilter Pre logic");
            return chain.filter(exchange).then(Mono.fromRunnable(() ->
            {
                log.info("CFilter Post logic");
            }));
        }

        @Override
        public int getOrder()
        {
            return HIGHEST_PRECEDENCE + 300;
        }
    }


    @Slf4j
    static class MyAuthFilter implements GlobalFilter, Ordered {

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            log.info("MyAuthFilter Permission filter");
            String token = exchange.getRequest().getHeaders().getFirst("token");
            if (StringUtils.isBlank(token)) {
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }

            return chain.filter(exchange);
        }

        @Override
        public int getOrder() {
            return HIGHEST_PRECEDENCE + 400;
        }
    }

}

Four global filters are defined, in the order of a > b > C > MyAuthFilter. The global filter MyAuthFilter determines whether the token exists. If the token does not exist, it returns a 401 status code, indicating that there is no access permission. Use Postman to execute the request, as shown in Figure 5-7.

5.5.3 local filter

The steps to define a local filter are as follows.
(1) You need to implement GatewayFilter, Ordered and related methods
(2) Package GatewayFilter to generate GatewayFilterFactory
(3) GatewayFilterFactory is added to the filter factory and registered in the spring container.
(4) Configure in the configuration file. If not configured, this filter rule will not be enabled.
Next, the local filter is defined. For the user ID verification of the request header, if there is no user ID request header, the status code 406 is returned directly. The code is as follows.

@Component
public class UserIdCheckGatewayFilterFactory extends AbstractGatewayFilterFactory<Object>
{
    @Override
    public GatewayFilter apply(Object config)
    {
        return new UserIdCheckGateWayFilter();
    }

    @Slf4j
    static class UserIdCheckGateWayFilter implements GatewayFilter, Ordered
    {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            String url = exchange.getRequest().getPath().pathWithinApplication().value();
            log.info("request URL:" + url);
            log.info("method:" + exchange.getRequest().getMethod());
            //Get header
            String userId = exchange.getRequest().getHeaders().getFirst("user-id");
            log.info("userId: " + userId);

            if (StringUtils.isBlank(userId))
            {
                log.info("*****Head verification failed, please enter in the head  user-id");
                //Termination request, direct response
                exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                return exchange.getResponse().setComplete();
            }
            return chain.filter(exchange);
        }

        //   The lower the value, the higher the priority
        @Override
        public int getOrder()
        {
            return HIGHEST_PRECEDENCE;
        }
    }

}

Configuration file application The YML code is as follows.

spring:
  cloud:
    gateway:
      routes:        
        - id: service14
          uri: http://127.0.0.1:9001
          predicates:
            - Path=/{segment}
      default-filters:
        - PrefixPath=/payment
        - UserIdCheck

5.6 advanced features

5.6.1 fuse degradation

In the distributed system, the gateway serves as the entrance of traffic, so a large number of requests will enter the gateway and initiate calls to other services. Other services will inevitably fail to call (timeout and exception). In case of failure, the requests cannot be stacked on the gateway, and they need to fail quickly and return to the client. To realize this requirement, we must fuse on the gateway Downgrade operation.
Why does the request fail on the gateway need to be quickly returned to the client? Because when a client request fails, the request will always accumulate on the gateway. Of course, there is only one such request, and the gateway is sure to have no problem (if one request can cause the whole system to crash, the system can be taken off the shelf), but too much accumulation on the gateway will cause great pressure on the gateway and even the whole service, Even the whole service went down. Therefore, some services and pages should be degraded strategically, so as to alleviate the pressure of server resources, ensure the normal operation of core business, and maintain the correct response of customers and most customers. Therefore, the request failure on the gateway needs to be quickly returned to the client.
The CircuitBreaker filter wraps the gateway route in the circuit breaker using the Spring Cloud CircuitBreaker API.
Spring Cloud CircuitBreaker supports multiple fuse libraries that can be used with Spring Cloud Gateway. For example, Spring Cloud supports Resilience4J out of the box. To enable the Spring Cloud CircuitBreaker filter, the steps are as follows.
1. Add dependency

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>

2. Configuration file

server:
  port: 9005
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: service14
          uri: http://127.0.0.1:9001
          predicates:
            - Path=/payment/{segment}
          filters:
            - name: CircuitBreaker
              args:
                name: backendA
                fallbackUri: forward:/fallbackA

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:9004/eureka

resilience4j:
  circuitbreaker:
    configs:
      default:
        failureRateThreshold: 30 #Percentage of failed requests. Beyond this percentage, the CircuitBreaker changes to OPEN
        slidingWindowSize: 10 #Size of sliding window, configure COUNT_BASED indicates 10 requests, and time is configured_ Based means 10 seconds
        minimumNumberOfCalls: 5 #The minimum number of requests. Only when the number of requests reaches this number in the sliding window can the circuit breaker's judgment be triggered
        slidingWindowType: TIME_BASED #Type of sliding window
        permittedNumberOfCallsInHalfOpenState: 3 #When CircuitBreaker is in half_ The number of requests allowed to pass in the open state
        automaticTransitionFromOpenToHalfOpenEnabled: true #Set true to automatically change from OPEN to HALF_OPEN, even if there is no request
        waitDurationInOpenState: 2s #From OPEN to half_ Time to wait for OPEN status
        recordExceptions: #Exception list
          - java.lang.Exception
    instances:
      backendA:
        baseConfig: default
      backendB:
        failureRateThreshold: 50
        slowCallDurationThreshold: 2s #Slow call time threshold. Calls above this threshold are regarded as slow calls, and the proportion of slow calls is increased.
        slowCallRateThreshold: 30 #Slow call percentage threshold. The circuit breaker considers the call time greater than slowCallDurationThreshold as slow call. When the slow call proportion is greater than the threshold, the circuit breaker opens and degrades the service
        slidingWindowSize: 10
        slidingWindowType: TIME_BASED
        minimumNumberOfCalls: 2
        permittedNumberOfCallsInHalfOpenState: 2
        waitDurationInOpenState: 120s #From OPEN to half_ Time to wait for OPEN status

3. Global filter
Create a global filter and print the fuse status with the following code

@Component
@Slf4j
public class CircuitBreakerLogFilter implements GlobalFilter, Ordered {

    @Autowired
    private CircuitBreakerRegistry circuitBreakerRegistry;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String url = exchange.getRequest().getPath().pathWithinApplication().value();
        log.info("url : {} status : {}", url, circuitBreakerRegistry.circuitBreaker("backendA").getState().toString());
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return HIGHEST_PRECEDENCE;
    }
}

4. Degradation method

@RestController
@Slf4j
public class FallbackController {

    @GetMapping("/fallbackA")
    public ResponseEntity fallbackA() {
        return ResponseEntity.ok("Service unavailable, degraded");
    }
}

Use JMeter tool to send 20 requests simultaneously within 1 second to trigger the circuit breaker backendA fusing condition. The circuit breaker opens. After 2 seconds, the fuse automatically enters the half open state (automatic transition from opentohalfopenenabled: true, waitduration in openstate: 2S), as shown in Figure 5-8.

After the next 2 seconds, request the fuse to be in the half open state again, and then start the payment micro service. The service can access the fuse normally and close it.

5.6.2 unified cross domain request

1. Cross domain introduction
Cross domain request means that the domain of the current request is different from the domain of the resource pointed to by the request. The domain here refers to such a concept: we believe that if the protocol + domain name + port number are the same, it is the same domain.
For example: suppose a domain name is AAA Cn, which initiates a resource path for AAA The Ajax request of CN / books / getbookinfo is in the same domain, because the protocol, domain name and port number of the resource path are consistent with the current domain (in the example, the protocol name is http by default, and the port number is 80 by default). However, if you initiate a resource, the path is BBB The Ajax request of COM / pay / purchase is a cross domain request, because the domains are inconsistent. At the same time, due to security problems, this request will be limited by the same origin policy.
Show me how to create index HTML, send ajax test across domains, and the code is as follows.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="./js/jquery/jquery-1.10.2.min.js"></script>
    <script>
        function sendAjax() {
            $.ajax({
                method: 'GET',
                url: "http://127.0.0.1:9001/payment/123",
                contentType: 'application/json; charset=UTF-8',
                success: function(o) {
                    alert(o.id);
                    alert(o.message);
                }
            });
        }
    </script>
</head>
<body>
    <button onclick="sendAjax();" >send ajax</button>
</body>
</html>

Through the above index HTML, send the request, because the browser has the same origin policy, there will be cross domain access problems.
Although the homology restriction is necessary at the security level, sometimes the homology strategy will affect our reasonable use. In order to avoid the limitation of developed applications, there are many ways to bypass the homology strategy, such as jsonp and CORS. You can use @ CrossOrigin with the following code.

@RestController
@RequestMapping("/payment")
@CrossOrigin
public class PaymentController {

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

    @GetMapping("/{id}")
    public ResponseEntity<Payment> payment(@PathVariable("id") Integer id) {
        Payment payment = new Payment(id, "Payment succeeded, service port=" + serverPort);
        return ResponseEntity.ok(payment);
    }

}

2. Cross domain configuration
Now the request passes through the gatway gateway. Cross domain access can be uniformly configured through the gateway. The code is as follows.

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowed-origin-patterns: "*" # spring boot2.4 configuration
#            allowed-origins: "*"
            allowed-headers: "*"
            allow-credentials: true
            allowed-methods:
              - GET
              - POST
              - DELETE
              - PUT
              - OPTION

Keywords: Java Microservices

Added by Sj0wKOoMel on Sat, 26 Feb 2022 12:01:35 +0200