Spring Cloud 之 Gateway.

First, the difference between the Gateway and Zuul

Zuul based servlet 2.5 (works with 3.x), use blocking API. It does not support any long-term connections, such as websocket.

Gateway built on the Spring Framework 5, Project Reactor and Spring Boot 2, the use of non-blocking API. Support Websocket, because of its tight integration with Spring, so it is a better developer experience.

Why Spring Cloud Zuul initially chose to use open source Netflix a few years ago as a gateway, and later chose the Gateway self-built it? There is a saying that a high-performance version of the Zuul2 After a number of bounced checks, for such integration experts Spring may be reluctant to continue to wait, so Spring Cloud Gateway came into being.

This article does performance Spring Cloud Gateway and Zuul's as much to say, is almost certain that the Gateway as a gateway is now the main push Spring Cloud, Finchley after the release of better than zuul 1.x Gateway whole series of performance and functionality.

Second, Quick Start

Let's build a simple gateway based on the Eureka registry, Gateway does not read too much into all the functions do, after all, the official document has been written in great detail, or you can read the Chinese translation of the document .

SpringBoot version number: 2.1.6.RELEASE

SpringCloud version number: Greenwich.RELEASE

1. pom.xml

    <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-hystrix</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-starter-data-redis-reactive</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
  • spring-cloud-starter-gateway: Spring Cloud Gateway start classes
  • spring-cloud-starter-netflix-hystrix: Hystrix fuse as a gateway program
  • spring-cloud-starter-netflix-eureka-client: the gateway into the Eureka registry management
  • spring-boot-starter-data-redis-reactive: limiting embodiment, Spring Cloud Gateway default to achieve limiting redis
  • spring-boot-starter-actuator: Gateway to monitor the routing information.

2. application.yml

spring:
  application:
    name: cloud-gateway
  redis:
    host: 127.0.0.1
    timeout: 3000
    password: xxxx
    jedis:
      pool:
        max-active: 8
        max-idle: 4
  cloud:
    gateway:
      enabled: true
      metrics:
        enabled: true
      discovery:
        locator:
          enabled: true
      routes:
        # 普通服务的路由配置
        - id: cloud-eureka-client
          uri: lb://cloud-eureka-client
          order: 0
          predicates:
            - Path=/client/**
          filters:
            #  parts 参数指示在将请求发送到下游之前,要从请求中去除的路径中的节数。比如我们访问 /client/hello,调用的时候变成 http://localhost:2222/hello
            - StripPrefix=1
            # 熔断器
            - name: Hystrix
              args:
                name: fallbackcmd
                # 降级处理
                fallbackUri: forward:/fallback
            # 限流器
            # 这定义了每个用户 10 个请求的限制。允许 20 个突发,但下一秒只有 10 个请求可用。
            - name: RequestRateLimiter
              args:
                # SPEL 表达式获取 Spring 中的 Bean,这个参数表示根据什么来限流
                key-resolver: '#{@ipKeyResolver}'
                # 允许用户每秒执行多少请求(令牌桶的填充速率)
                redis-rate-limiter.replenishRate: 10
                # 允许用户在一秒内执行的最大请求数。(令牌桶可以保存的令牌数)。将此值设置为零将阻止所有请求。
                redis-rate-limiter.burstCapacity: 20
        # websocket 的路由配置
        - id: websocket service
          uri: lb:ws://serviceid
          predicates:
            - Path=/websocket/**
management:
  endpoints:
    web:
      exposure:
        # 开启指定端点
        include: gateway,metrics
eureka:
  client:
    service-url:
      defaultZone: http://user:password@localhost:1111/eureka/
  • spring.redis *:. redis configuration in order to achieve limiting the Gateway program.
  • eureka.client *:. eureka registry information.
  • spring.cloud.gateway.discovery.locator.enabled: The gateway is configured to create the registry based on the use of compatible DiscoveryClient registered service routing.
  • spring.cloud.gateway.routes *:. Configuring Routing Information
    • id: Routing unique identification
    • uri: routing forwarding address to route beginning lb, the ribbon will be processed, the processing is forwarded to the service of cloud-eureka-client. It can also be configured to http standalone routing - http: // localhost: 2222.
    • order: routing execution order (the order of execution can also be understood as a filter), the order of execution is executed from small to large, a higher value is interpreted as a lower priority.
    • predicates: routing asserted, matching the access path is "/ client / **" request.
    • filters: Filter the gateway is configured
  • management.endpoints.web.exposure.include: exposure actuator can access the endpoints
    • / Actuator / gateway / routes to view the routing list
    • / Actuator / gateway / globalfilters retrieves the global routing - takes effect on all routes
    • / Actuator / gateway / routefilters retrieved local routing - may be arranged to effect only a single route
    • / Actuator / gateway / refresh routing cache cleanup
    • /actuator/metrics/gateway.requests obtain routing request data

3. GatewayApplication.java

@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {

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

    /**
     * 限流的键定义,根据什么来限流
     */
    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }

}

Third, the filter

Spring Cloud Gateway with Zuul Similarly, there are filter "pre" and "post" in two ways. Client requests go through "pre" type of filter, and then forwards the request to a specific business services, business services after receiving the response, and then through the "post" type of filter, and finally returns a response to the client.

The difference is that the Zuul, filter addition into "pre" and "post" two ways filter, in the Spring Cloud Gateway, filter scope can be divided from the other two, one is for a single gateway to route filter, it requires that a single route as arranged in the above application.yml Filters; the other is directed to all routes Global Gateway filter, no separate configuration, valid for all routes.

Global Filters

We usually achieve authentication, sign test, current limit, the log output, with global filters.

GlobalFilter by implementing the interface defined global filter from the Gateway; Ordered interface implemented or used by @Order annotation to define the execution order of the filter, the order of execution is executed from small to large, a higher value is interpreted as a lower priority.

    @Bean
    @Order(-1)
    public GlobalFilter a() {
        return (exchange, chain) -> {
            log.info("first pre filter");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("third post filter");
            }));
        };
    }

    @Bean
    @Order(0)
    public GlobalFilter b() {
        return (exchange, chain) -> {
            log.info("second pre filter");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("second post filter");
            }));
        };
    }

    @Bean
    @Order(1)
    public GlobalFilter c() {
        return (exchange, chain) -> {
            log.info("third pre filter");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("first post filter");
            }));
        };
    }

The highest priority filter, its "pre" filter executed first, "post" filter implemented latest.

Partial filter

We define a "pre" type of local filters:

@Component
public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {
    
    public PreGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            //If you want to build a "pre" filter you need to manipulate the
            //request before calling chain.filter
            ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
            //use builder to manipulate the request
            ServerHttpRequest request = builder.build();
            return chain.filter(exchange.mutate().request(request).build());
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }
}

Wherein the desired filter parameters in the PreGatewayFilterFactory.Config. Then, then we need to do is to filter configured on the local routing needs, according to the agreement SpringBoot greater than the configured thought, we only need to configure PreGatewayFilterFactory.java in front of the parameters on the line, that is,

spring:
  cloud:
    gateway:
      routes:
        - id: cloud-eureka-client
          uri: lb://cloud-eureka-client
          order: 0
          predicates:
            - Path=/client/**
          filters:
            - pre

tips: possible to read the default Gateway provides several filters, such StripPrefixGatewayFilterFactory.java like.

Fourth, dynamic routing

Spring Cloud Gateway for dynamic routing using mainly RouteDefinitionWriter the Bean:

public interface RouteDefinitionWriter {

    Mono<Void> save(Mono<RouteDefinition> route);

    Mono<Void> delete(Mono<String> routeId);
}

Prior to read some articles online, basically custom controller and access parameters, then use RouteDefinitionWriter dynamic gateway. However, when I read the document Spring Cloud Gateway, Gateway has been found to provide similar functionality:

@RestControllerEndpoint(id = "gateway")
public class GatewayControllerEndpoint implements ApplicationEventPublisherAware {

    /*---省略前面代码---*/

    @PostMapping("/routes/{id}")
    @SuppressWarnings("unchecked")
    public Mono<ResponseEntity<Void>> save(@PathVariable String id, @RequestBody Mono<RouteDefinition> route) {
        return this.routeDefinitionWriter.save(route.map(r ->  {
            r.setId(id);
            log.debug("Saving route: " + route);
            return r;
        })).then(Mono.defer(() ->
            Mono.just(ResponseEntity.created(URI.create("/routes/"+id)).build())
        ));
    }

    @DeleteMapping("/routes/{id}")
    public Mono<ResponseEntity<Object>> delete(@PathVariable String id) {
        return this.routeDefinitionWriter.delete(Mono.just(id))
                .then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build())))
                .onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build()));
    }

     /*---省略后面代码---*/
}

To create a routing, POST request transmission / Actuator / Gateway / routes / id_route_to_create {} , JSON structure parameters, specific parameters of the data structure:

{
  "id": "first_route",
  "predicates": [{
    "name": "Path",
    "args": {"_genkey_0":"/first"}
  }],
  "filters": [],
  "uri": "http://www.uri-destination.org",
  "order": 0
}]

To delete a route, sending a DELETE request / actuator / gateway / routes / { id_route_to_delete}

V. Appendix

Guess you like

Origin www.cnblogs.com/jmcui/p/11259200.html