api gateway assertions and filters

1. What is an api gateway?

The so-called API gateway refers to the unified entrance of the background system. It encapsulates the internal structure of the application and provides the unified routing service to the client. Some common logic which is not related to the functions of the business itself can be implemented here, such as authentication, authentication, monitoring, routing forwarding and so on.
To put it plainly, find services through the gateway.

2. Common api gateways

Ngnix+lua
Using nginx's reverse proxy and load balancing to achieve load balancing on api servers and highly available lua is a scripting language for writing simple logic. nginx supports lua scripting Kong
Developed based on Nginx+Lua, it has high performance and stability. There are several available plug-ins (current limiting, authentication, etc.) that can be used out of the box. Problem: Only Http protocol is supported; Secondary development makes it difficult to expand freely. Provides management API s, lacking easier control and configuration.
Zuul Netflix Open Source Gateway, rich in features, developed with JAVA, is easy to secondary development problems: lack of control, unable to dynamically configure; More dependent components; Processing Http requests relies on a Web container and does not perform as well as Nginx
Spring Cloud Gateway
The gateway service Spring developed to replace Zuul is described below.

3. Steps for use

1.Spring Cloud Gateway

Spring Cloud Gateway is Spring's technology based on Spring 5.0, Spring Boot 2.0 and Project Reactor
A gateway has been developed to provide a simple and effective unified API routing management method for the micro-service architecture. Its goal is to replace
Netflix Zuul, which not only provides a unified routing method, but also provides basic gateway functionality based on the Filter chain, such as:
Full, monitoring and current limiting.

2. Advantages and disadvantages

Advantage
Powerful performance: 1.6 times the first generation gateway Zuul
Powerful: Built-in many useful functions, such as forwarding, monitoring, current limiting, etc.
Elegant design, easy to expand
shortcoming
Its implementation relies on Netty and WebFlux, is not a traditional Servlet programming model, and is costly to learn
It cannot be deployed in Servlet containers such as Tomcat, Jetty, etc. It can only be executed as a jar package
Spring Boot version 2.0 and above is required to support

3. Traditional filters

The code is as follows (example):

@WebFilter(filterName="MyFliter",urlPatterns="/api/share/*")
public class MyFliter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filter Before entering");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("filter After entering");
    }

    @Override
    public void destroy() {

    }
}

//Add comments to the main program
//@ServletComponentScan("filter package name")

4. Use gateway

4.1module

4.2 Add a pom dependency

The code is as follows (example):

<?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_nacos</artifactId>
        <groupId>com.csdn</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud_gateway</artifactId>
        <dependencies>
            <!--Limiting algorithm use redis-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
            </dependency>
            <!--gateway-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
            </dependency>
            <!--Service Registration-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <dependency>
                <groupId>com.csdn</groupId>
                <artifactId>springcloud_common</artifactId>
                <version>${project.version}</version>
                <!--gateway Responsive web Programming Patterns We want to incorporate traditional web Programming model shaving-->
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-web</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>

        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>

            </plugins>
        </build>
    </project>

4.3yaml Configuration

The code is as follows (example):

server:
  port: 7000
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # Register gateway with nacos
    gateway:
      discovery:
        locator:
          enabled: true # Let gateway get service information from nacos
      routes:
        - id: share-6002   # As long as the unique identification is present
          uri: lb://share-6002 #Real Address
          order: 1
          predicates:      # Reason only if the condition in the assertion is met
            - Path=/api/share/**,/admin/share/**
        - id: user-6001   # As long as the unique identification is present
          uri: lb://user-6001 #Real address
          order: 1
          predicates:      # Reason only if the condition in the assertion is met
            - Path=/api/user/**,/admin/user/**

4.4 Main program opens comment@EnableDiscoveryClient

The common point between @EnableDiscoveryClient and @EnableEurekaClient is that they both enable the registry to discover and scan the service.

@EnableEurekaClient is only available for registration as Eureka;@ EnableDiscoveryClient can be another registry.
The code is as follows (example):

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

4. Implementation Process

1: Basic concepts
Route is one of the most basic components in gateway, representing a specific routing information carrier. The following information is mainly defined:

--
idRoute identifier, different from other routes
uriThe route points to the destination uri, which is the microservice to which client requests are ultimately forwarded.
orderFor sorting between multiple routes, the smaller the number, the higher the priority of matching.
predicateThe purpose of an assertion is to make conditional judgments, and only when all assertions return true will the route actually be executed.
filterFilters are used to modify request and response information.


DispatcherHandler: Scheduler for all requests, load request distribution
RoutePredicate HandlerMapping: A routing predicate matcher that is used for routing lookups and returns the corresponding WebHandler after finding the route. DispatcherHandler traverses the Handler Mapping collection for processing in turn
FilteringWebHandler: A WebHandler that handles requests using a Filter chain list.
RoutePredicateHandlerMapping finds the route and returns the corresponding FilteringWebHandler to process the request. The FilteringWebHandler is responsible for assembling the Filter list and calling the list to process the request.

5. Assertions

Predicate (predicate) is used to make conditional judgments, and only when all the assertions return true will the route actually be executed.
An assertion is a condition under which routing forwarding can take place
Links: https://www.cnblogs.com/wgslucky/p/11396579.html.

5.1: Custom Assertions

Add Custom Assertion Class

package gateway.pradicate;

import com.alibaba.nacos.common.utils.StringUtils;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

@Component
public class AgeRoutePredicateFactory extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {

    // 1:Configuration class, used to receive corresponding parameters in the configuration file
    @Data
    @NoArgsConstructor
    public static class Config {
        private int minAge;//18 corresponds to the first parameter in the assertion configuration
        private int maxAge;//60 corresponds to the second parameter in the assertion configuration
    }
    // 2:Constructor
    public AgeRoutePredicateFactory() {
        super(Config.class);
    }
    //3: Read the parameter values in the configuration file and assign them to the properties in the configuration class
    public List<String> shortcutFieldOrder() {
        //The order of this location must correspond to the order of values in the configuration file
        return Arrays.asList("minAge", "maxAge");
    }
    //4: Assertion logic
    public Predicate<ServerWebExchange> apply(Config config) {
        return new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                // 4.1 Receive foreground incoming age parameters
                String ageStr = serverWebExchange.getRequest().getQueryParams().getFirst("Age");

                //4.2 First decide if it is empty
                if (StringUtils.isNotEmpty(ageStr)) {
                    //3If not null, then route logic
                    int age = Integer.parseInt(ageStr);
                    if (age < config.getMaxAge() && age > config.getMinAge()) {
                        return true;
                    } else {
                        return false;
                    }
                }
                return false;
            }
        };
    }
}

Configure under routes that need to be judged

5.2: Filter

Links: https://www.cnblogs.com/fx-blog/p/11751977.html.
Classification: Local filters (acting on a route) Global filters (acting on all routes) Gateway's filters can be divided into two types from their scope of action: GatewayFilter and GlobalFilter. GatewayFilter: Applies to a single route or a grouped route.
GlobalFilter: Applies to all routes.

Examples of built-in filters:

Note Access from Gateway

Custom local filter

Add Custom Log Configuration

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

    //1: Configuration class receives configuration parameters
    @Data
    @NoArgsConstructor
    public static class Config {
        private boolean consoleLog;
    }
    
    //2: Constructor [Fixed Writing]
    public LogGatewayFilterFactory() {
        super(Config.class);
    }

    //3: Read the parameters in the configuration file and assign them to the configuration class
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("consoleLog");
    }

    //4: Filter logic
    @Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter() {
            Long start = System.currentTimeMillis();
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                // Before entering the service
                if (config.isConsoleLog()) {
                    log.info("{} Get into {}",new Date(), exchange.getRequest().getPath());
                }
                // Call the service and define the logic after the service returns
                // Note that if at this point you just need to go into the previous validation, you can return chain without the logic after the service has finished executing. Filter (exchange)
                return chain.filter(exchange).then(Mono.fromRunnable(()->{
                    if (config.isConsoleLog()) {
                        Long end = System.currentTimeMillis();
                        log.info("{} Sign out {}. Total time consumed:{}",new Date(), exchange.getRequest().getPath(),(end-start));
                    }
                }));

            }
        };
    }
}

Global filter
Global filters work on all routes and do not need to be configured. Global filters enable unified validation of privileges, security validation, etc.

Customize Global Filters

//Customizing global filters requires implementing the GlobalFilter and Ordered interfaces														
												
@Component														
public class MyGloablFilter implements GlobalFilter, Ordered {														
														
    // Filtering logic														
    @Override														
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {														
														
        // 1 controller before entering														
        System.out.println("Before entering MyGloablFilter");														
        // 2 Release														
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {														
            // Write the logical response returned in the callback														
            System.out.println("from controller After returning");														
        }));																								
        //3 Callbacks																								
    }																									
    // The smaller the number returned, the more effective it will be														
    @Override														
    public int getOrder() {														
        return 0;														
    }														
}														

Keywords: Java

Added by garfx on Sun, 26 Dec 2021 22:38:23 +0200