Gateway custom local filter and custom global filter

What is Gateway

The core of the Spring Cloud Gateway component is a series of filters, which can forward (route) requests sent by clients to pairs
Microservices should be. Spring Cloud Gateway is a firewall and agent added at the forefront of the whole microservice, which hides the IP port information of the microservice node,
So as to strengthen safety protection. Spring Cloud Gateway itself is also a micro service, which needs to be registered with Eureka service registry.

Gateway core concepts

  • route
    Routing information consists of an ID, a destination URL, a set of assertion factories and a set of filters. If the route assertion is true, the request URL matches the configured route.
  • Predicate the input type of the assertion function in the Spring Cloud Gateway is Spring
    ServerWebExchange in the 5.0 framework. The assertion function of Spring Cloud Gateway allows developers to define and match any information from HTTP Request, such as request header and parameters.
  • Filter a standard Spring WebFilter. Spring Cloud
    There are two types of filters in Gateway: Gateway Filter and Global Filter
    Filter. The filter will modify the request and response

One of the important functions of Gateway is to realize the authentication of request. This action is often implemented through the filter provided by the Gateway

Use of Gateway

  1. Introducing Gateway dependencies
<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>
</dependencies>
  1. Write startup class
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
  1. Write configuration
server:
  port: 10010
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
     # The routing id can be written at will
      - id: user-service-route
     # Service address of agent
      uri: HTTP://127.0.0.1:9091
     # Route assertion, you can configure the mapping path
      predicates:
        - Path=/user/**
eureka:
  client:
    service-url:
      defaultZone: HTTP://127.0.0.1:10086/eureka
  instance:
    prefer-ip-address: true

What is a Gateway filter

One of the important functions of Gateway is to realize the authentication of request. This action is often implemented through the filter provided by the Gateway

Common built-in filters:

Filter nameexplain
AddRequestHeaderAdd a Header to the matching request
AddRequestParametersAdd parameters to the request route on the match
AddResponseHeaderAdd a Header for the response returned from the gateway
StripPrefixRemove the prefix from the request path on the match

Routing prefix

If the request address of the client is inconsistent with the service address of the microservice, you can add and remove the path prefix by configuring the path filter.

Address of service provider: http://127.0.0.1:9091/user/8

  • Add prefix: add a prefix path to the request address and then use it as the service address of the agent;

http://127.0.0.1:10010/8 --> http://127.0.0.1:9091/user/8 Add prefix path / user

  • Remove prefix: remove some prefix paths from the path in the request address, and then serve as the service address of the agent

http://127.0.0.1:10010/api/user/8 --> http://127.0.0.1:9091/user/8 Remove prefix path / API

add prefix

In the gateway, you can add the address in the mapping path by configuring the filter PrefixPath of the route;

spring:
  cloud:
    gateway:
      routes:
        #The id of the route can be arbitrary
        - id: user-service-rote
          #Proxy's microservice address
          #  uri: http://127.0.0.1:9999
          uri: lb://user-service
          # Route assertion, you can configure the mapping path
          predicates:
            - Path=/**
          filters:
            # Add prefix to request path
            - PrefixPath=/user

PrefixPath=/xxx specifies the prefix to be added to the route. That is:

  • PrefixPath=/user http://localhost:10010/8 -->http://localhost:9091/user/8
  • PrefixPath=/user/abc http://localhost:10010/8 -->http://localhost:9091/user/abc/8

add prefix

In the gateway, the address in the mapping path can be removed by configuring the route filter StripPrefix:

spring:
  cloud:
    gateway:
      routes:
        #The id of the route can be arbitrary
        - id: user-service-rote
          #Proxy's microservice address
          #  uri: http://127.0.0.1:9999
          uri: lb://user-service
          # Route assertion, you can configure the mapping path
       	  predicates:
            - Path=/api/user/**
          filters:
            # It means filtering 1 path, 2 means two paths, and so on
            - StripPrefix=1

The number of prefixes to be removed from the route is specified by StripPrefix=1. For example, the path / api/user/1 will be proxied to / user/1. That is:

  • StripPrefix=1 http://localhost:10010/api/user/8 -->http://localhost:9091/user/8
  • StripPrefix=2 http://localhost:10010/api/user/8 -->http://localhost:9091/8

Execution lifecycle

The Filter life cycle of Spring Cloud Gateway is similar to that of Spring MVC. There are two interceptors: "pre" and "post". "Pre" and "post" are called separately before and after the request is executed.


The pre and post here can be implemented before and after the filter method is executed by the GatewayFilterChain of the filter

Usage scenario

  • Request authentication: generally, before the GatewayFilterChain executes the filter method, if it is found that there is no access permission, it will directly return null.
  • Exception handling: generally, after the GatewayFilterChain executes the filter method, the exception is recorded and returned.
  • Statistics of service call duration: the gateway filterchain performs statistics according to the time before and after the filter method is executed.

Custom local filter

Requirements: in the filter (MyParamGatewayFilterFactory) http://localhost:10010/user/8? The value of the parameter name in name = YH is obtained and output to the console

Add a gateway filter to the application.yml file:

Insert picture description here]( https://img-blog.csdnimg.cn/0bafd595c32841a9872c31236d4a442a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bm95ri455m96YWl,size_20,color_FFFFFF,t_70,g_se,x_16)

Create a config file and create a class named MyParamGatewayFiterFactory
be careful! Name xxxgatewayfiterfactory, and xxxx is yml user-defined name + GatewayFiterFactory; The GatewayFiterFactory does not or has an error. The following error will occur

Failed to start bean 'eurekaAutoServiceRegistration';
 nested exception is reactor.core.Exceptions$ErrorCallbackNotImplemented: 
java.lang.IllegalArgumentException: Unable to find GatewayFilterFactory with name MyParam


Inherit MyParamGatewayFiterFactory from the parent class abstractgatewayfilterfactory < MyParamGatewayFiterFactory. Config > and add @ Component annotation

Create a Config class to read the filter configuration parameters, create a String type parameter in the class corresponding to the filter parameter name configured in the application.yml configuration file, and generate the get set method


Override method of parent class:

Override the parent GatewayFilter method. It can be seen from the source code that the required return type is
ServerWebExchange exchange, GatewayFilterChain chain

Complete code snippet

package com.yh.gateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

@Component
public class MyParamGatewayFilterFactory extends AbstractGatewayFilterFactory<MyParamGatewayFilterFactory.Config> {

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


        @Override
        public List<String> shortcutFieldOrder() {
        return Arrays.asList("param");
        }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // http://localhost:10010/user/8?name=yh config.param ==> name
            //Gets the parameter value of the parameter name corresponding to param in the request parameter
            ServerHttpRequest request = exchange.getRequest();
            if (request.getQueryParams().containsKey(config.param)){
                request.getQueryParams().get(config.param).forEach((v) -> {
                    System.out.print("--Local filter--Get parameters "+config.param+"="+ v);
                });
            }
          return chain.filter(exchange);//Execute request
        };
    }


    //Read parameters of filter configuration
    public static class Config{
        //Corresponds to the filter parameter name configured in the application.yml configuration file
        private String param;

        public String getParam() {
            return param;
        }

        public void setParam(String param) {
            this.param = param;
        }
    }
}

Output results:

Custom global filter

Requirements: write a global filter and check whether the request carries the token request header in the filter. If the token request header exists, it will be released; If the token is empty or does not exist, set the returned status code as: unauthorized and no longer executed.

Create a global filter class to implement GlobalFilter,; Ordered is the filter execution order

@Component
public class MyGlobalFilter  implements GlobalFilter, Ordered {


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return null;
    }

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

@Component
public class MyGlobalFilter  implements GlobalFilter, Ordered {


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("Global filter");
        String token = exchange.getResponse().getHeaders().getFirst("token");//Get the first request header named token
        //No permission
        if (StringUtils.isBlank(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);//If not, return status code 401
            return exchange.getResponse().setComplete();
        }
        //Have authority
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        //The smaller the value, the more priority is given to execution
        return 1;
    }
}

Open postman. When there is no request header, the result is 401

Add request header token successfully accessed

Keywords: filter gateway

Added by pelleas on Thu, 09 Sep 2021 22:15:40 +0300