Service gateway Spring Cloud Gateway

  • brief introduction
  • predicate
  • filter
  • Current limiting
  • Cooperate with registry routing and forwarding
  • use

Spring Cloud Gateway is the second-generation gateway framework officially launched by Spring Cloud, replacing Zuul gateway. As the of traffic, gateway plays a very important role in microservice system. The common functions of gateway include routing forwarding, permission verification, current limit control and so on.

brief introduction

effect

  • Protocol conversion, routing and forwarding
  • Traffic aggregation, traffic monitoring and log output
  • As the front-end project of the whole system, it controls the flow and limits the function of flow
  • As the front-end boundary of the system, external traffic can only access the system through the gateway
  • Permission can be judged at the gateway layer
  • Caching can be done at the gateway layer

Workflow

The client sends a request to the Spring Cloud Gateway. If the Gateway Handler Mapping determines that the request matches the route (predicate is used at this time), it will be sent to the Gateway web handler for processing.

The Gateway web handler processes requests through a series of filter chains. The reason why the filter chain is divided by dotted lines is that the filter chain can perform filtering logic before or after sending the proxy request.

Execute all "pre" filter logic before making proxy requests. After issuing the proxy request and receiving the response from the proxy service, the "post" filter logic is executed. When all "pre" filter logic is executed, authentication, current limiting, log output and other functions are often performed, as well as the change of request header and protocol conversion; After the response is received after forwarding, the logic of all "post" filters will be executed, where the response data can be modified, such as response header, protocol conversion, etc.

predicate

Introduction to predict

The function of predicate is to match the request with the route. It determines which route a request takes.

Predict comes from the interface of Java 8. Predicate takes 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 request parameter verification of the interface and judge whether new and old data have changed and need to be updated. add – and, or – or, negative – not.

Spring Cloud Gateway has built-in predictions. The source code of these predictions is at org.com springframework. cloud. gateway. handler. In the Predict package, various predictions are listed as follows:

There are many types of Predicate in the figure above

  • Time type predicted (afterroutepredictefactory beforeroutepredictefactory between routepredictefactory). Only requests that meet specific time requirements will enter this predict and be handled by the router
  • Cookie type cookie routepredicatefactory. The specified cookie meets regular matching before entering this router
  • And predictions of host, method, path, querparam and remoteaddr types. Each prediction will judge whether the current client request meets the current requirements. If so, it will be handed over to the current request for processing.
  • If there are many predictions and a request satisfies multiple predictions, the first one will take effect in the order of configuration.

Predict actual combat

The case comes from official documents: http://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.0.0.RELEASE/single/spring-cloud-gateway.html

Method Route Predicate Factory

The Method Route Predicate Factory requires a parameter, that is, the type of request. For example, GET type requests are forwarded to this route. Add the following configuration to the project configuration file:

spring:
  profiles:
    active: method_route

---
spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: http://httpbin.org:80/get
        predicates:
        - Method=GET
  profiles: method_route

In the above configuration, all get type requests will be routed and forwarded to the configured uri. Simulate the get type request with curl command, and you will get the correct return result.

$ curl localhost:8081

Simulating a post request with the curl command returns a 404 result.

$ curl -XPOST localhost:8081

Source download

https://github.com/forezp/SpringCloudLearning/tree/master/sc-f-gateway-predicate

filter

Predict determines which route the request is processed by. Before routing, it needs to be processed by a "pre" filter. After the response is returned, it can be processed by a "post" filter.

Parameter verification, permission verification, traffic monitoring, log output, protocol conversion, etc. can be done in the "pre" type filter. In the "post" type filter, you can modify the response content and response header, log output, traffic monitoring, etc.

effect

When we have many services and the client requests the Api of each service, each service needs to do the same things, such as authentication, flow limiting, log output, etc.

For such repetitive work, an Api Gateway service with global permission control, flow restriction and log output can be added to the upper layer of the micro service, and then the request can be forwarded to the specific business service layer. This Api Gateway service serves as a service boundary. External requests to access the system must first pass through the gateway layer.

life cycle

The client's request first passes through a "pre" type filter, and then forwards the request to a specific business service. After receiving the response from the business service, it is processed through a "post" type filter, and finally returns the response to the client.

In addition to the "pre" and "post" filters, the filter can be divided into two other types from the scope of action. One is the gateway filter for a single route, and its writing in the configuration file is similar to predict; The other is the global gateway filer for all routes.

gateway filter

Filters allow you to modify incoming HTTP requests or outgoing HTTP responses in some way. Filters can be limited to certain request paths. Spring Cloud Gateway includes many built-in GatewayFilter factories.

The gateway filter factory is similar to the Predicate factory described in the previous article, and is in the configuration file application Configuration in YML. The GatewayFilter Factory configured in the configuration file will eventually be processed by the corresponding filter factory class.

Following the idea that the Convention is greater than the configuration, you only need to configure the name of the GatewayFilter Factory in the configuration file instead of writing all the class names. For example, AddRequestHeaderGatewayFilterFactory only needs to write AddRequestHeader in the configuration file instead of all the class names.

The list of built-in filter factories of Spring Cloud Gateway is as follows:

AddRequestHeader GatewayFilter Factory

Create the project and introduce relevant dependencies, including spring boot version 2.0.5, spring Cloud version Finchley, and gateway dependencies as follows:

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

In the configuration file of the project, add the following configuration:

server:
  port: 8081
spring:
  profiles:
    active: add_request_header_route

---
spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: http://httpbin.org:80/get
        filters:
        - AddRequestHeader=X-Request-Foo, Bar
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
  profiles: add_request_header_route

In add_ request_ header_ In route configuration, the routing address is configured as http://httpbin.org:80/get , the router has AfterPredictFactory and one filter is addrequestheadergatewayfilterfactory (the contract is written as AddRequestHeader).

The AddRequestHeader filter factory will add a pair of request headers with the name of X-Request-Foo and the value of Bar to the request header.

The source code of AddRequestHeaderGatewayFilterFactory is as follows:

public class AddRequestHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

	@Override
	public GatewayFilter apply(NameValueConfig config) {
		return (exchange, chain) -> {
			ServerHttpRequest request = exchange.getRequest().mutate()
					.header(config.getName(), config.getValue())
					.build();

			return chain.filter(exchange.mutate().request(request).build());
		};
    }

}

As can be seen from the above code, create a new ServerHttpRequest based on the old ServerHttpRequest, add a request header to the new ServerHttpRequest, then create a new ServerWebExchange, submit the filter chain and continue filtering.

Start the project and simulate the request through curl command:

curl localhost:8081

The final display from http://httpbin.org:80/get Received the request and responded as follows:

{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Connection": "close",
    "Forwarded": "proto=http;host=\"localhost:8081\";for=\"0:0:0:0:0:0:0:1:56248\"",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.58.0",
    "X-Forwarded-Host": "localhost:8081",
    "X-Request-Foo": "Bar"
  },
  "origin": "0:0:0:0:0:0:0:1, 210.22.21.66",
  "url": "http://localhost:8081/get"
}

It can be seen from the above response that a request header such as X-Request-Foo is indeed added to the request header, and the AddRequestHeader filter factory configured in the configuration file takes effect.

RewritePath GatewayFilter Factory

A very powerful function in Nginx service startup is to rewrite paths. Spring Cloud Gateway also provides such a function by default, which Zuul does not have. Add the following configuration to the configuration file:

spring:
  profiles:
    active: rewritepath_route
---
spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: https://blog.csdn.net
        predicates:
        - Path=/foo/**
        filters:
        - RewritePath=/foo/(?<segment>.*), /$\{segment}
  profiles: rewritepath_route

In the above configuration, all paths starting from / foo / * * will hit the configured router and execute the logic of the filter.

In this case, the RewritePath filter factory is configured, which rewrites / foo / (?. *) to {segment} and forwards it to https://blog.csdn.net . For example, if you request localhost: 8081 / foo / XXXXXX on the web page, the request will be forwarded to https://blog.csdn.net/xxxxxxx Page.

Custom filter

Spring cloud gateway has built-in 19 powerful filter factories, which can meet the needs of many scenarios. In spring cloud gateway, the filter needs to implement GatewayFilter and Ordered interfaces. Write a RequestTimeFilter with the following code:

public class RequestTimeFilter implements GatewayFilter, Ordered {

    private static final Log log = LogFactory.getLog(GatewayFilter.class);
    private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";

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

        exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
        return chain.filter(exchange).then(
                Mono.fromRunnable(() -> {
                    Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
                    if (startTime != null) {
                        log.info(exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
                    }
                })
        );

    }

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

In the above code, the int getOrder() method in Ordered is used to set the priority of the filter. The higher the value, the lower the priority. There is also a filterI(exchange,chain) method. In this method, the start time of the request is recorded and saved in ServerWebExchange. Here is a "pre" type filter, and then chain The run() method in the inner class of filter is equivalent to the "post" filter, where the time consumed by the request is printed. Then register the filter in the router with the following code:

    @Bean
    public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
        // @formatter:off
        return builder.routes()
                .route(r -> r.path("/customer/**")
                        .filters(f -> f.filter(new RequestTimeFilter())
                                .addResponseHeader("X-Response-Default-Foo", "Default-Bar"))
                        .uri("http://httpbin.org:80/get")
                        .order(0)
                        .id("customer_filter_router")
                )
                .build();
        // @formatter:on
    }

Restart the program and simulate the request through curl command:

 curl localhost:8081/customer/123

Output the following log of request information on the program console:

2018-11-16 15:02:20.177  INFO 20488 --- [ctor-http-nio-3] o.s.cloud.gateway.filter.GatewayFilter   : /customer/123: 152ms

Custom filter factory

In the above custom filter, is there any way to customize the filter factory class? This allows you to configure filters in the configuration file. Now you need to implement a filter factory. When printing time, you can set parameters to decide whether to print. Viewing the source code of gatewayfilterfactory, you can find that the level of gatewayfilterfactory is as follows:

The top-level interface of the filter factory is GatewayFilterFactory. We can directly inherit its two abstract classes to simplify the development of AbstractGatewayFilterFactory and AbstractNameValueGatewayFilterFactory. The difference between these two abstract classes is that the former receives one parameter (like StripPrefix and the one we created) and the latter receives two parameters (like AddResponseHeader).

The top-level interface of the filter factory is GatewayFilterFactory. There are two abstract classes close to the specific implementation, namely AbstractGatewayFilterFactory and AbstractNameValueGatewayFilterFactory. The former receives a parameter, such as its implementation class RedirectToGatewayFilterFactory; The latter receives two parameters, such as its implementation class AddRequestHeaderGatewayFilterFactory. Now you need to print the requested log and use a parameter. At this time, you can refer to the writing method of RedirectToGatewayFilterFactory.

public class RequestTimeGatewayFilterFactory extends AbstractGatewayFilterFactory<RequestTimeGatewayFilterFactory.Config> {


    private static final Log log = LogFactory.getLog(GatewayFilter.class);
    private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";
    private static final String KEY = "withParams";

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

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

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
            return chain.filter(exchange).then(
                    Mono.fromRunnable(() -> {
                        Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
                        if (startTime != null) {
                            StringBuilder sb = new StringBuilder(exchange.getRequest().getURI().getRawPath())
                                    .append(": ")
                                    .append(System.currentTimeMillis() - startTime)
                                    .append("ms");
                            if (config.isWithParams()) {
                                sb.append(" params:").append(exchange.getRequest().getQueryParams());
                            }
                            log.info(sb.toString());
                        }
                    })
            );
        };
    }


    public static class Config {

        private boolean withParams;

        public boolean isWithParams() {
            return withParams;
        }

        public void setWithParams(boolean withParams) {
            this.withParams = withParams;
        }

    }
}

In the above code, an anonymous class of GatewayFilter is created in the apply(Config config) method. The specific implementation logic is the same as before, except that the logic of whether to print the request parameters is added, and the switch of this logic is Config isWithParams(). The static internal class Config is designed to receive the parameter service of boolean type. The variable name inside can be written at will, but the method List shortcutFieldOrder() should be overridden.

It should be noted that the constructor of the class must call the constructor of the lower parent class to pass the Config type, otherwise ClassCastException will be reported

Finally, you need to register the Bean of RequestTimeGatewayFilterFactory class with the Srping Ioc container in the Application class of the project startup file.

    @Bean
    public RequestTimeGatewayFilterFactory elapsedGatewayFilterFactory() {
        return new RequestTimeGatewayFilterFactory();
    }

You can then configure the following in the configuration file:

spring:
  profiles:
    active: elapse_route

---
spring:
  cloud:
    gateway:
      routes:
      - id: elapse_route
        uri: http://httpbin.org:80/get
        filters:
        - RequestTime=false
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
  profiles: elapse_route

Start the project and visit localhost: 8081 on the browser? Name = forezp, you can see on the console that the log outputs the time consumed by the request and the request parameters.

global filter

Spring Cloud Gateway is divided into GatewayFilter and GlobalFilter according to the scope of action. The differences between the two are as follows:

  • GatewayFilter: need to pass spring cloud. routes. Filters are configured under specific routes and only work on the current route or through spring cloud. Default filters is configured globally and acts on all routes
  • GlobalFilter: a global filter, which does not need to be configured in the configuration file and acts on all routes. It is finally packaged into a filter recognizable by GatewayFilterChain through the GatewayFilterAdapter. It is a core filter that converts the URI of the request service and route into the request address of the real service. It does not need to be configured. It is loaded during system initialization, And act on each route.

The GlobalFilter built in the Spring Cloud Gateway framework is as follows:

In the figure above, each GlobalFilter acts on each router and can meet most requirements. However, if you encounter business customization, you may need to write a GlobalFilter to meet your needs. The following case will describe how to write your own GlobalFilter, which will verify whether the request contains the request parameter "token", and how to not forward the route if it does not contain the request parameter "token", otherwise normal logic will be executed. The code is as follows:

public class TokenFilter implements GlobalFilter, Ordered {

    Logger logger=LoggerFactory.getLogger( TokenFilter.class );
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (token == null || token.isEmpty()) {
            logger.info( "token is empty..." );
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

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

The TokenFilter above needs to implement GlobalFilter and Ordered interfaces, which is very similar to the implementation of GatewayFilter. Then obtain the ServerHttpRequest according to ServerWebExchange, and then complete the request according to whether the ServerHttpRequest contains the parameter token. If not, terminate the forwarding. Otherwise, execute the normal logic.

Then, you need to inject TokenFilter into the Spring Ioc container in the project startup class. The code is as follows:

@Bean
public TokenFilter tokenFilter(){
        return new TokenFilter();
}

Start the project and use the curl command to request:

 curl localhost:8081/customer/123

You can see that the request was terminated without being forwarded, and the following log was printed on the console:

2018-11-16 15:30:13.543  INFO 19372 --- [ctor-http-nio-2] gateway.TokenFilter                      : token is empty...

The above log shows that the request entered the logic without "token".

Source download

https://github.com/forezp/SpringCloudLearning/tree/master/sc-f-gateway-predicate

Current limiting

Common current limiting algorithms

Counter algorithm

The counter algorithm uses the counter to limit the current, which is a little simple and rough. Generally, we will limit the number of requests that can pass in one second. For example, the current limit qps is 100. The implementation idea of the algorithm is to count the time from the first request. In the next 1s, for each request, add 1 to the count. If the accumulated number reaches 100, Then all subsequent requests will be rejected. After 1s, restore the count to 0 and restart the count. The specific implementation can be as follows: for each service call, the AtomicLong#incrementAndGet() method can be used to add 1 to the counter and return the latest value, which can be compared with the threshold. I believe we all know that this implementation method has a disadvantage: if I have passed 100 requests in the first 10ms of unit time, I can only refuse the requests in the next 990ms. We call this phenomenon "spike phenomenon"

Leaky bucket algorithm

In order to eliminate the "prick phenomenon", the leaky bucket algorithm can be used to limit the flow. The name of the leaky bucket algorithm is very vivid. There is a container inside the algorithm, which is similar to the funnel used in life. When the request comes in, it is equivalent to water pouring into the funnel, and then flowing out slowly and uniformly from the small opening at the lower end. No matter how much flow is above, the speed of outflow from below remains unchanged. No matter how unstable the service caller is, the flow is limited by the leaky bucket algorithm, and the request is processed every 10 milliseconds. Because the processing speed is fixed and the incoming speed of requests is unknown, many requests may come in suddenly. Requests that have not been processed in time are put in the bucket first. Since it is a bucket, there must be a capacity limit. If the bucket is full, new incoming requests will be discarded.

In terms of algorithm implementation, a queue can be prepared to save requests. In addition, a scheduled executorservice can periodically obtain requests from the queue and execute them. Multiple concurrent executions can be obtained at one time.

This algorithm also has disadvantages after use: it can not deal with short-time burst traffic.

Token Bucket

In a sense, token bucket algorithm is an improvement of leaky bucket algorithm. Bucket algorithm can limit the rate of request calls, while token bucket algorithm can limit the average rate of calls and allow a certain degree of burst calls. In the token bucket algorithm, there is a bucket for storing a fixed number of tokens. There is a mechanism in the algorithm, which puts tokens into the bucket at a certain rate. Each request call needs to obtain the token first. Only when you get the token can you have the opportunity to continue execution. Otherwise, you can choose to wait for the available token or refuse directly. The action of putting tokens is continuous. If the number of tokens in the bucket reaches the upper limit, the tokens will be discarded. Therefore, this situation exists. There are a large number of available tokens in the bucket. At this time, incoming requests can be directly executed with the tokens. For example, if qps is set to 100, there will be 100 tokens in the bucket one second after the initialization of the current limiter, At this time, the service has not been fully started. When the service is provided, the current limiter can resist 100 instantaneous requests. Therefore, only when there is no token in the bucket will the request wait, and finally it is equivalent to executing at a certain rate.

Implementation idea: a queue can be prepared to save tokens. In addition, tokens are regularly generated through a thread pool and placed in the queue. For each request, a token is obtained from the queue and continues to be executed.

Spring Cloud Gateway current limiting

In Spring Cloud Gateway, there are Filter filters, so you can implement the above three filters in "pre" type filters. However, as the most basic function of the gateway, the Spring Cloud Gateway officially provides the RequestRateLimiterGatewayFilterFactory class, which is suitable for Redis and lua scripts to implement the token bucket.

The specific implementation logic is in the RequestRateLimiterGatewayFilterFactory class, and the lua script is in the folder shown in the following figure:

Firstly, the start dependency of gateway and the reactive dependency of redis are introduced into the pom file of the project. The code is as follows:

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

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

Make the following configuration in the configuration file:

server:
  port: 8081
spring:
  cloud:
    gateway:
      routes:
      - id: limit_route
        uri: http://httpbin.org:80/get
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
        filters:
        - name: RequestRateLimiter
          args:
            key-resolver: '#{@hostAddrKeyResolver}'
            redis-rate-limiter.replenishRate: 1
            redis-rate-limiter.burstCapacity: 3
  application:
    name: gateway-limiter
  redis:
    host: localhost
    port: 6379
    database: 0

In the above configuration file, the port of the specified program is 8081, redis information is configured, and the current limiting filter of RequestRateLimiter is configured. The filter needs to be configured with three parameters:

  • burstCapacity, total capacity of token bucket.
  • replenishRate, the average rate of token bucket filling per second.
  • Key resolver, the name of the Bean object of the parser for the current limiting key. It uses a SpEL expression to get the Bean object from the Spring container according to #{@ beanName}.

KeyResolver needs to implement the resolve method. For example, if the current is limited according to Hostname, it needs to be judged by hostAddress. After implementing KeyResolver, you need to register the Bean of this class in the Ioc container.

public class HostAddrKeyResolver implements KeyResolver {

    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
    }

}

 @Bean
    public HostAddrKeyResolver hostAddrKeyResolver() {
        return new HostAddrKeyResolver();
    }

You can limit the current according to the uri. At this time, the KeyResolver code is as follows:

public class UriKeyResolver  implements KeyResolver {

    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        return Mono.just(exchange.getRequest().getURI().getPath());
    }

}

 @Bean
    public UriKeyResolver uriKeyResolver() {
        return new UriKeyResolver();
    }

You can also limit the flow in the user's dimension:

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

Use jmeter for pressure measurement, configure 10thread to request lcoalhost:8081, and the cycle interval is 1s. It can be seen from the pressure test results that some requests pass and some requests fail. Check the key s in redis through the redis client. As follows:

It can be seen that RequestRateLimiter uses redis for current limiting, and stores two keys in redis. Pay attention to the meaning of these two keys. You can see the lua source code.

Source download

https://github.com/forezp/SpringCloudLearning/tree/master/sc-f-gateway-limiter

Cooperate with the registry for routing and forwarding

Previously, hard coding was used for routing and forwarding. Now, how does Spring Cloud Gateway cooperate with the service registry for routing and forwarding.

Project introduction

The version of spring boot used in this case is 2.0.3 Release, the spring cloud version is Finchley RELEASE. Three projects are involved in the, namely, the registration center Eureka server, the service provider service hi and the service gateway service gateway, as follows:

project name

port

effect

eureka-server

8761

Registration Center eureka server

service-hi

8762

Service provider eurka client

service-gateway

8081

Routing gateway eureka client

Among the three projects, service hi and service gateway are registered with the registration center Eureka server. The user's request first passes through the service gateway. According to the path, the predict of the gateway determines which router to enter. After the router is processed by various filters, it is finally routed to specific business services, such as service hi. As shown in the figure:

The two projects Eureka server and service hi are directly copied from another article of mine https://blog.csdn.net/forezp/article/details/81040925 , there is no repetition here. You can view the source code. See the link at the end of the article for the source code address. The service hi service exposes a RESTFUL interface "/ Hi". Now focus on the service gateway.

Detailed introduction to gateway project

The dependencies required by the project are introduced into the gateway project, including the start dependency of Eureka client and the start dependency of gateway. The code is as follows:

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

In the project configuration file application In YML, the startup port of the specified program is 8081, and the registered address, gateway configuration and other information are as follows:

server:
  port: 8081

spring:
  application:
    name: sc-gateway-service
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lowerCaseServiceId: true
          
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

Among them, spring cloud. gateway. discovery. locator. Enabled is true, indicating that the gateway enables the function of service registration and discovery, and the spring cloud gateway automatically creates a router for each service according to service discovery, which forwards the request path starting with the service name to the corresponding service. spring.cloud.gateway.discovery.locator.lowerCaseServiceId configures the service name on the request path to lowercase (because the service name is converted to uppercase when registering with the registry). For example, the request path of / service hi / * is routed and forwarded to the service named service hi.

Request localhost: 8081 / service hi / hi on the browser? Name = 1323, the web page gets the following response:

hi 1323 ,i am from port:8762

In the above example, when sending a request to the gateway service, the url must be prefixed with the service name service hi before it can be forwarded to the service hi. Before forwarding, the service hi will be removed. So can I customize the request path? After all, the service name is sometimes too long, or the service name cannot be routed for historical reasons. It needs to be customized and forwarded to the specific service. The answer is yes, yes. You only need to modify the project configuration file application YML, the specific configuration is as follows:

spring:
  application:
    name: sc-gateway-server
  cloud:
    gateway:
      discovery:
        locator:
          enabled: false
          lowerCaseServiceId: true
      routes:
      - id: service-hi
        uri: lb://SERVICE-HI
        predicates:
          - Path=/demo/**
        filters:
          - StripPrefix=1

In the above configuration, a predict of Path is configured. All requests starting with / demo / * * will be forwarded to the address with uri lb://SERVICE-HI, which is the load balancing address of service hi service. Use the filter of StripPrefix to remove / demo before forwarding. At the same time, spring cloud. gateway. discovery. locator. Change enabled to false. If not, the previous localhost: 8081 / service hi / hi? The request address such as name = 1323 can also be accessed normally, because two router s are created for each service.

Request localhost: 8081 / demo / hi on the browser? Name = 1323, the browser returns the following response:

hi 1323 ,i am from port:8762

The result returned is the same as we expected.

Source download

https://github.com/forezp/SpringCloudLearning/tree/master/sc-f-gateway-cloud

use

Engineering construction

Create a new gateway project. The project directory is as follows:

The gateway needs to be registered with nacos, and the following dependencies need to be introduced:

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

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

In the configuration file application POM file:

server:
  port: 5000

spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: false
          lowerCaseServiceId: true
      routes:
        - id: provider
          uri: lb://provider
          predicates:
            - Path=/provider/**
          filters:
            - StripPrefix=1
        - id: consumer
          uri: lb://consumer
          predicates:
            - Path=/consumer/**
          filters:
            - StripPrefix=1

Please read the related tutorials at the end of the article to explain the configuration, which will not be repeated here.

Relevant notes shall be added to the start-up document of the project:

 @SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {

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

}

Start the three projects of gateway\consumer\provider successively, and have been successfully registered in nacos:

Enter on the browser http://localhost:5000/consumer/hi-feign, the browser returns a response:

hello feign, i'm provider ,my port:8762

Create a simple route

In the spring cloud gateway, use the Bean of RouteLocator for routing forwarding, process the request, and finally forward it to the downstream service of the target. In this case, the request is forwarded to http://httpbin.org:80 On this address. The code is as follows:

@SpringBootApplication
@RestController
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    @Bean
    public RouteLocator myRoutes(RouteLocatorBuilder builder) {
       return builder.routes()
        .route(p -> p
            .path("/get")
            .filters(f -> f.addRequestHeader("Hello", "World"))
            .uri("http://httpbin.org:80"))
        .build();
    }
    
    }

In the above myRoutes method, a RouteLocatorBuilder bean is used to create routes. In addition to creating routes, RouteLocatorBuilder allows you to add various predictions and filters. Predictions assertion means that specific routes are processed according to specific request rules. Filters are various filters, Used to make various judgments and modifications to requests.

The route created above allows the request "/ get" to be forwarded to“ http://httpbin.org/get ”. On the route configuration, we have added a filter, which will add a header to the request. The key is hello and the value is world.

Start the springboot project on the browser http://localhost:8080/get , the browser displays as follows:

{
  "args": {}, 
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", 
    "Accept-Encoding": "gzip, deflate, br", 
    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", 
    "Cache-Control": "max-age=0", 
    "Connection": "close", 
    "Cookie": "_ga=GA1.1.412536205.1526967566; JSESSIONID.667921df=node01oc1cdl4mcjdx1mku2ef1l440q1.node0; screenResolution=1920x1200", 
    "Forwarded": "proto=http;host=\"localhost:8080\";for=\"0:0:0:0:0:0:0:1:60036\"", 
    "Hello": "World", 
    "Host": "httpbin.org", 
    "Upgrade-Insecure-Requests": "1", 
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", 
    "X-Forwarded-Host": "localhost:8080"
  }, 
  "origin": "0:0:0:0:0:0:0:1, 210.22.21.66", 
  "url": "http://localhost:8080/get"
}

It can be seen that when we request "/ get" from the gateway project, the gateway will forward the project request to“ http://httpbin.org/get ”And before forwarding, add a filter, which will add a header to the request, with the key as hello and the value as world.

Note that HTTP bin shows the header hello and the value world of the request.

Using Hystrix

You can use hystrix in the spring cloud gateway. Hystrix is a service component of spring cloud and plays a very important role in microservice system. Hystrix is used as a filter in the spring cloud gateway. The code is as follows:

   @Bean
    public RouteLocator myRoutes(RouteLocatorBuilder builder) {
        String httpUri = "http://httpbin.org:80";
        return builder.routes()
            .route(p -> p
                .path("/get")
                .filters(f -> f.addRequestHeader("Hello", "World"))
                .uri(httpUri))
            .route(p -> p
                .host("*.hystrix.com")
                .filters(f -> f
                    .hystrix(config -> config
                        .setName("mycmd")
                        .setFallbackUri("forward:/fallback")))
                .uri(httpUri))
            .build();
    }

In the above code, we use another router, which uses the host to assert whether the request enters the route. When the requested host has "*. hystrix.com", it will enter the router. There is a hystrix filter in the router, which can configure the name, and the logical address of the directional fallback. For example, in this case, it is redirected to "/ fallback".

Now write a logic of "/ fallback":

 @RequestMapping("/fallback")
    public Mono<String> fallback() {
        return Mono.just("fallback");
    }

Mono is a Reactive stream that outputs a "fallback" string.

Use curl to execute the following command:

 curl --dump-header - --header 'Host: www.hystrix.com' http://localhost:8080/delay/3

The response returned is:

fallback

Visible, with hostwww hystrix. Com's request implements the fallback logic of hystrix.

Source download

https://github.com/forezp/SpringCloudLearning/tree/master/sc-2020-chapter2

reference resources:

  • Spring Cloud Gateway first experience: https://www.fangzhipeng.com/springcloud/2018/11/06/sc-f-gateway1.html
  • Predict of Spring Cloud Gateway: https://www.fangzhipeng.com/springcloud/2018/12/05/sc-f-gateway2.html
  • filter of spring cloud gateway: https://www.fangzhipeng.com/springcloud/2018/12/21/sc-f-gatway3.html
  • Current limit of spring cloud gateway: https://www.fangzhipeng.com/springcloud/2018/12/22/sc-f-gatway4.html
  • Service registration and discovery of spring cloud gateway: https://www.fangzhipeng.com/springcloud/2018/12/23/sc-f-gateway5.html
  • Use spring cloud gateway as the service gateway: https://www.fangzhipeng.com/springcloud/2021/04/03/sc-2020-gateway.html
  • Official case of Spring Cloud: https://spring.io/guides/gs/gateway

Added by j007ha on Wed, 05 Jan 2022 13:02:19 +0200