Filter of Gateway service Gateway

The article has been included in my Github collection. Welcome Star: https://github.com/yehongzhi/learningSummary

Write in front

The previous article wrote the Gateway's predict (for routing and forwarding), so this article introduces another main core, that is, filter.

What does the filter do? What is the workflow like? See the figure below:

It is obvious from the figure that Filter is required before and after requesting back-end services. Therefore, the role of Filter is clear. Parameter verification, traffic monitoring, logging and modifying request content can be done in prefilter (request pre-processing), and response content can be modified in postfilter (request post-processing).

filter

Filter s are divided into local and global types:

  • Local filter (subclass of gatewayfilter) acts on a single route. If you need to use global routing, you need to configure Default Filters.
  • Global filter (a subclass of globalfilter) does not need to configure routes. System initialization works on all routes.

Local filter

Spring cloud gateway has many built-in routing filters, which are generated by the factory class of GatewayFilter.

AddRequestParameter GatewayFilter

This filter can add parameters to the request.

For example, I have an interface with a userName parameter in the consumer service. I want to add a userName=yehongzhi parameter to the gateway when requesting routing forwarding.

@RequestMapping(value = "/getOrder",method = RequestMethod.GET)
public String getOrder(@RequestParam(name = "userName") String userName) {
    return "Gets the incoming user name:" + userName;
}

The configuration is as follows:

spring:
  cloud:
    gateway:
      routes:
        - id: add_request_parameter
          uri: http://localhost:8081/getOrder
          predicates:
            - Method=GET
            - Path=/getOrder
          filters:
            - AddRequestParameter=userName,yehongzhi

So when I request a gateway, enter http://localhost:9201/getOrder , we can see the default userName.

StripPrefix GatewayFilter

This filter removes a specified number of path prefixes.

For example, if I want to remove the first level of the path prefix of the request gateway, I can configure it as follows:

spring:
  cloud:
    gateway:
      routes:
        - id: strip_prefix_gateway
          uri: http://localhost:8081
          predicates:
            - Path=/consumer/**
          filters:
            - StripPrefix=1

When requesting a path http://localhost:9201/consumer/getDetail/1 , results can be obtained.

Equivalent to request http://localhost:8081/getDetail/1 , the result is the same.

PrefixPath GatewayFilter

In contrast to the previous filter, this filter adds a specified prefix to the original path.

spring:
  cloud:
    gateway:
      routes:
        - id: prefix_path_gateway
          uri: http://localhost:8081
          predicates:
            - Path=/getUserInfo/**
          filters:
            - PrefixPath=/consumer

When requested http://localhost:9201/getUserInfo/1 When, follow the request http://localhost:8081/consumer/getUserInfo/1 It's the same.

Hystrix GatewayFilter

Of course, the gateway has a fusing mechanism, so the filter integrates Hystrix to realize the fusing function. How to use it? First, we need to introduce the maven dependency of Hystrix.

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

Add the fallback() method to the gateway service

@RestController
public class FallBackController {
    @RequestMapping("/fallback")
    public String fallback(){
        return "The system is busy, please try again later!";
    }
}

The gateway service is configured as follows. When there is an error in forwarding the GET request route, the service degradation will be triggered:

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

At this time, we stop the service of 8081, so that the gateway cannot request the corresponding service, thus triggering service degradation.

RequestRateLimiter GatewayFilter

The filter can provide the function of limiting the flow. The RateLimiter implementation is used to determine whether to allow the current request to continue. If the request is too large, the HTTP 429- too many request status will be returned by default. How? First, we have to introduce Maven dependency.

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

Then add a configuration class.

@Configuration
public class LimiterConfig {

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

Then configure the following to add a current limiting policy to GET requests:

spring:
  cloud:
    gateway:
      routes:
        - id: hystrix_filter
          uri: http://localhost:8081
          predicates:
            - Method=GET
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1 #The number of requests allowed to be processed per second
                redis-rate-limiter.burstCapacity: 2 #Maximum number of requests processed per second
                key-resolver: "#{@ipKeyResolver}" #Current limiting policy, Bean corresponding to the policy
  redis:
    port: 6379
    host: 192.168.1.5 #redis address

Then start the service and continuously request the address http://localhost:9201/getDetail/1 , it will trigger current limiting and report 429 error.

Because there are too many built-in filters, we won't list them one by one here. Interested students can learn by themselves on the official website.

Custom local filter

If the built-in local filter cannot meet the requirements, we have to use a custom filter. How to use it? As an example, we customize a filter for the white list. Only those whose userName is in the white list can access it. Those who are not in the white list will return a 401 error code (Unauthorized).

The local filter needs to implement the GatewayFilter and Ordered interfaces. The code is as follows:

public class WhiteListGatewayFilter implements GatewayFilter, Ordered {
 //Whitelist collection
    private List<String> whiteList;
 //Initialize whitelist through constructor
    WhiteListGatewayFilter(List<String> whiteList) {
        this.whiteList = whiteList;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String userName = exchange.getRequest().getQueryParams().getFirst("userName");
        //The white list is not empty, and the userName is included in the white list before you can access it
        if (!CollectionUtils.isEmpty(whiteList) && whiteList.contains(userName)) {
            return chain.filter(exchange);
        }
        //If the whitelist is empty or userName is not in the whitelist, 401 is returned
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        return exchange.getResponse().setComplete();
    }

    //Priority. The smaller the value, the higher the priority
    @Override
    public int getOrder() {
        return 0;
    }
}

Then define a filter factory and inject it into the Spring container. The code is as follows:

@Component
public class WhiteListGatewayFilterFactory extends AbstractConfigurable<WhiteListGatewayFilterFactory.Config> implements GatewayFilterFactory<WhiteListGatewayFilterFactory.Config> {

    private static final String VALUE = "value";

    protected WhiteListGatewayFilterFactory() {
        super(WhiteListGatewayFilterFactory.Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList(VALUE);
    }

    @Override
    public GatewayFilter apply(Config config) {
        //Get configured whitelist
        String whiteString = config.getValue();
        List<String> whiteList = new ArrayList<>(Arrays.asList(whiteString.split(",")));
        //Create an instance of WhiteListGatewayFilter and return
        return new WhiteListGatewayFilter(whiteList);
    }
 //Used to receive configuration parameters
    public static class Config {

        private String value;

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }
}

Finally, we can add the following configuration in the application.yaml configuration file:

spring:
  cloud:
    gateway:
      routes:
        - id: white_list_filter
          uri: http://localhost:8081
          predicates:
            - Method=GET
          filters:
            - WhiteList=yehongzhi #The white list is configured after the equal sign, separated by commas

Then start the project. First request localhost:9201/getDetail/1 without userName. 401 will be returned as expected and cannot be accessed.

Request an address with userName=yehongzhi http://localhost:9201/getDetail/1?userName=yehongzhi is in the white list, so it can be accessed normally.

Global filter

The global filter acts on all routes during system initialization and does not need to be configured separately. The interface definition class of the global filter is GlobalFilter, and the Gateway itself has many built-in filters. Let's open the class diagram to see:

Let's introduce some representative ones, such as the global filter LoadBalancerClientFilter for load balancing.

LoadBalancerClientFilter

The filter will resolve to URIs starting with lb: / /, for example:

spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        service: ${spring.application.name}
    gateway:
      routes:
        - id: consumer
          uri: lb://consumer # uses the lb protocol. consumer is the service name. IP address configuration is no longer used
          order: 1
          predicates:
            - Path=/consumer/** 

The global filter will get the service name consumer, and then get the ServiceInstance service instance through LoadBalancerClient. Reassemble the requested url according to the obtained service instance.

This is an example of a global filter application. It works globally and does not need to be configured. Next, let's explore the custom global filter. Suppose you need to count the total number of times a user's IP address accesses the gateway. What should you do?

Custom global filter

To customize the global filter, you need to implement the GlobalFilter interface and the Ordered interface.

@Component
public class IPAddressStatisticsFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        InetSocketAddress host = exchange.getRequest().getHeaders().getHost();
        if (host == null || host.getHostName() == null) {
            exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
            return exchange.getResponse().setComplete();
        }
        String hostName = host.getHostName();
        AtomicInteger count = IpCache.CACHE.getOrDefault(hostName, new AtomicInteger(0));
        count.incrementAndGet();
        IpCache.CACHE.put(hostName, count);
        System.out.println("IP Address:" + hostName + ",Number of visits:" + count.intValue());
        return chain.filter(exchange);
    }

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

//Cache for save times
public class IpCache {
    public static final Map<String, AtomicInteger> CACHE = new ConcurrentHashMap<>();
}

Start the project, then request the service, and you can see the console print results.

IP Address: 192.168.1.4,Number of visits: 1
IP Address: 192.168.1.4,Number of visits: 2
IP Address: 192.168.1.4,Number of visits: 3
IP Address: localhost,Number of visits: 1
IP Address: localhost,Number of visits: 2
IP Address: localhost,Number of visits: 3
IP Address: 192.168.1.4,Number of visits: 4

summary

The functions of the service gateway are basically realized through the predictions in the previous article and the Filters in this article, including routing forwarding, permission interception, traffic statistics, traffic control, service fusing, logging and so on. Therefore, gateway service is a very important part of microservice architecture. Many front-line Internet companies will also develop service gateways by themselves. Therefore, mastering the service gateway is a necessary skill for back-end development. Thank you for reading.

Added by ultranet on Fri, 12 Nov 2021 08:58:58 +0200