• Spring Cloud Gateway简单入门,强大的微服务网关


    我最新最全的文章都在 南瓜慢说 www.pkslow.com ,欢迎大家来喝茶!

    1 简介

    见名知义,Spring Cloud Gateway是用于微服务场景的网关组件,它是基于Spring WebFlux,也就是Reactive的。从实现原理上,它的性能应该是比Zuul会更好。

    它的工作原理如下图所示:

    简单而言就是通过一连串的Filter处理匹配到特定规则Predicates的请求。所以最主要就是做了两件事:

    (1)哪些请求可以被它处理,由Predicates决定;

    (2)如何处理,由Filters决定。

    2 路由条件判断Predicates

    2.1 时间匹配After

    表示在什么时间之后才算满足条件匹配路由:

    spring:
      cloud:
        gateway:
          routes:
          - id: after_route
            uri: https://example.org
            predicates:
            - After=2020-01-20T17:42:47.789-07:00[America/Denver]
    

    2.2 时间匹配Before

    表示在什么时间之前匹配路由:

    spring:
      cloud:
        gateway:
          routes:
          - id: before_route
            uri: https://example.org
            predicates:
            - Before=2017-01-20T17:42:47.789-07:00[America/Denver]
    

    2.3 时间段匹配Between

    表示在什么时间段匹配路由:

    spring:
      cloud:
        gateway:
          routes:
          - id: between_route
            uri: https://example.org
            predicates:
            - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
    

    2.4 Cookie匹配

    表示通过判断Cookie的键值来匹配路由,其中值支持正则表达式:

    spring:
      cloud:
        gateway:
          routes:
          - id: cookie_route
            uri: https://example.org
            predicates:
            - Cookie=chocolate, ch.p
    

    2.5 请求头匹配Header

    表示通过判断Http请求的Header来匹配路由:

    spring:
      cloud:
        gateway:
          routes:
          - id: header_route
            uri: https://example.org
            predicates:
            - Header=X-Request-Id, d+
    

    2.6 主机名匹配Host

    通过判断Hostname来匹配路由:

    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: https://example.org
            predicates:
            - Host=**.somehost.org,**.anotherhost.org
    

    2.7 请求方法匹配Method

    表示通过判断请求方法来匹配路由:

    spring:
      cloud:
        gateway:
          routes:
          - id: method_route
            uri: https://example.org
            predicates:
            - Method=GET,POST
    

    2.8 请求路径匹配Path

    表示通过判断请求路径来匹配路由,很常用:

    spring:
      cloud:
        gateway:
          routes:
          - id: path_route
            uri: https://example.org
            predicates:
            - Path=/red/{segment},/blue/{segment}
    

    2.9 请求参数匹配Query

    表示通过判断请求参数来匹配路由:

    spring:
      cloud:
        gateway:
          routes:
          - id: query_route
            uri: https://example.org
            predicates:
            - Query=red, gree.
    

    2.10 IP地址匹配RemoteAddr

    表示通过判断IP地址来匹配路由:

    spring:
      cloud:
        gateway:
          routes:
          - id: remoteaddr_route
            uri: https://example.org
            predicates:
            - RemoteAddr=192.168.1.1/24
    

    2.11 权重匹配Weight

    通过权重来匹配路由:

    spring:
      cloud:
        gateway:
          routes:
          - id: weight_high
            uri: https://weighthigh.org
            predicates:
            - Weight=group1, 8
          - id: weight_low
            uri: https://weightlow.org
            predicates:
            - Weight=group1, 2
    

    3 功能强大的GatewayFilter

    Spring提供许多强大的GatewayFilter对请求进行处理。

    3.1 添加请求头

    给请求添加Header

    spring:
      cloud:
        gateway:
          routes:
          - id: add_request_header_route
            uri: https://example.org
            predicates:
            - Path=/red/{segment}
            filters:
            - AddRequestHeader=X-Request-Red, Blue-{segment}
    

    3.2 添加请求参数

    spring:
      cloud:
        gateway:
          routes:
          - id: add_request_parameter_route
            uri: https://example.org
            predicates:
            - Host: {segment}.myhost.org
            filters:
            - AddRequestParameter=foo, bar-{segment}
    

    3.3 添加返回Header

    spring:
      cloud:
        gateway:
          routes:
          - id: add_response_header_route
            uri: https://example.org
            predicates:
            - Host: {segment}.myhost.org
            filters:
            - AddResponseHeader=foo, bar-{segment}
    

    3.4 删除重复返回Header

    spring:
      cloud:
        gateway:
          routes:
          - id: dedupe_response_header_route
            uri: https://example.org
            filters:
            - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
    

    3.5 断路器Hystrix

    简单配置:

    spring:
      cloud:
        gateway:
          routes:
          - id: hystrix_route
            uri: https://example.org
            filters:
            - Hystrix=myCommandName
    

    较复杂配置:

    spring:
      cloud:
        gateway:
          routes:
          - id: hystrix_route
            uri: lb://backing-service:8088
            predicates:
            - Path=/consumingserviceendpoint
            filters:
            - name: Hystrix
              args:
                name: fallbackcmd
                fallbackUri: forward:/incaseoffailureusethis
            - RewritePath=/consumingserviceendpoint, /backingserviceendpoint
    

    3.6 断路器CircuitBreaker

    简单配置:

    spring:
      cloud:
        gateway:
          routes:
          - id: circuitbreaker_route
            uri: https://example.org
            filters:
            - CircuitBreaker=myCircuitBreaker
    

    较复杂配置:

    spring:
      cloud:
        gateway:
          routes:
          - id: circuitbreaker_route
            uri: lb://backing-service:8088
            predicates:
            - Path=/consumingServiceEndpoint
            filters:
            - name: CircuitBreaker
              args:
                name: myCircuitBreaker
                fallbackUri: forward:/inCaseOfFailureUseThis
            - RewritePath=/consumingServiceEndpoint, /backingServiceEndpoint
    

    3. 7 请求头改名

    spring:
      cloud:
        gateway:
          routes:
          - id: map_request_header_route
            uri: https://example.org
            filters:
            - MapRequestHeader=Blue, X-Request-Red
    

    3.8 路径添加前缀

    这个要注意和匹配路径区分,它是在匹配后再加个前缀:

    spring:
      cloud:
        gateway:
          routes:
          - id: prefixpath_route
            uri: https://example.org
            filters:
            - PrefixPath=/mypath
    

    请求/hello变成/mypath/hello

    3.9 重定向

    spring:
      cloud:
        gateway:
          routes:
          - id: prefixpath_route
            uri: https://example.org
            filters:
            - RedirectTo=302, https://acme.org
    

    3.10 删除请求头

    spring:
      cloud:
        gateway:
          routes:
          - id: removerequestheader_route
            uri: https://example.org
            filters:
            - RemoveRequestHeader=X-Request-Foo
    

    3.11 删除返回头

    spring:
      cloud:
        gateway:
          routes:
          - id: removeresponseheader_route
            uri: https://example.org
            filters:
            - RemoveResponseHeader=X-Response-Foo
    

    3.12 删除请求参数

    spring:
      cloud:
        gateway:
          routes:
          - id: removerequestparameter_route
            uri: https://example.org
            filters:
            - RemoveRequestParameter=red
    

    3.13 重写路径

    spring:
      cloud:
        gateway:
          routes:
          - id: rewritepath_route
            uri: https://example.org
            predicates:
            - Path=/red/**
            filters:
            - RewritePath=/red(?<segment>/?.*), ${segment}
    

    3.14 设置路径

    spring:
      cloud:
        gateway:
          routes:
          - id: setpath_route
            uri: https://example.org
            predicates:
            - Path=/red/{segment}
            filters:
            - SetPath=/{segment}
    

    3.15 设置请求头

    spring:
      cloud:
        gateway:
          routes:
          - id: setrequestheader_route
            uri: https://example.org
            predicates:
            - Host: {segment}.myhost.org
            filters:
            - SetRequestHeader=foo, bar-{segment}
    

    3.16 设置返回头

    spring:
      cloud:
        gateway:
          routes:
          - id: setresponseheader_route
            uri: https://example.org
            predicates:
            - Host: {segment}.myhost.org
            filters:
            - SetResponseHeader=foo, bar-{segment}
    

    3.17 设置返回状态码

    spring:
      cloud:
        gateway:
          routes:
          - id: setstatusstring_route
            uri: https://example.org
            filters:
            - SetStatus=BAD_REQUEST
          - id: setstatusint_route
            uri: https://example.org
            filters:
            - SetStatus=401
    

    3.18 去掉路径前缀

    spring:
      cloud:
        gateway:
          routes:
          - id: nameRoot
            uri: https://nameservice
            predicates:
            - Path=/name/**
            filters:
            - StripPrefix=2
    

    这配置请求/name/blue/red,实际就是请求nameservice/red,去掉两个前缀。

    3.19 重试Retry GatewayFilter

    想不到居然还有强大的重试功能:

    spring:
      cloud:
        gateway:
          routes:
          - id: retry_test
            uri: http://localhost:8080/flakey
            predicates:
            - Host=*.retry.com
            filters:
            - name: Retry
              args:
                retries: 3
                statuses: BAD_GATEWAY
                methods: GET,POST
                backoff:
                  firstBackoff: 10ms
                  maxBackoff: 50ms
                  factor: 2
                  basedOnPreviousValue: false
    

    3.20 请求大小限制

    spring:
      cloud:
        gateway:
          routes:
          - id: request_size_route
            uri: http://localhost:8080/upload
            predicates:
            - Path=/upload
            filters:
            - name: RequestSize
              args:
                maxSize: 5000000
    

    3.21 默认Filter

    如果希望对所有路由都生效,可以添加默认Filter

    spring:
      cloud:
        gateway:
          default-filters:
          - AddResponseHeader=X-Response-Default-Red, Default-Blue
          - PrefixPath=/httpbin
    

    4 全局Global Filters

    全局过滤器GlobalFilter接口和GatewayFilter的方法是一样的,但它是用于所有路由的。当请求过来时,整个Filter Chain是包含了所有的GlobalFilters和匹配上的GatewayFilters,执行顺序由getOrder()方法决定。

    如下:

    @Bean
    public GlobalFilter customFilter() {
        return new CustomGlobalFilter();
    }
    
    public class CustomGlobalFilter implements GlobalFilter, Ordered {
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            log.info("custom global filter");
            return chain.filter(exchange);
        }
    
        @Override
        public int getOrder() {
            return -1;
        }
    }
    

    5 一切皆可自定义

    Spring支持开发人员自定义PredicateGatewayFilterGlobalFilter

    5.1 自定义Predicate

    public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.Config> {
    
        public MyRoutePredicateFactory() {
            super(Config.class);
        }
    
        @Override
        public Predicate<ServerWebExchange> apply(Config config) {
            // grab configuration from Config object
            return exchange -> {
                //grab the request
                ServerHttpRequest request = exchange.getRequest();
                //take information from the request to see if it
                //matches configuration.
                return matches(config, request);
            };
        }
    
        public static class Config {
            //Put the configuration properties for your filter here
        }
    }
    

    5.2 自定义GatewayFilter

    Pre的过滤器:

    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
                return chain.filter(exchange.mutate().request(builder.build()).build());
            };
        }
    
        public static class Config {
            //Put the configuration properties for your filter here
        }
    }
    

    Post的过滤器:

    public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {
    
        public PostGatewayFilterFactory() {
            super(Config.class);
        }
    
        @Override
        public GatewayFilter apply(Config config) {
            // grab configuration from Config object
            return (exchange, chain) -> {
                return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                    ServerHttpResponse response = exchange.getResponse();
                    //Manipulate the response in some way
                }));
            };
        }
    
        public static class Config {
            //Put the configuration properties for your filter here
        }
    }
    

    5.3 自定义GlobalFilter

    @Bean
    public GlobalFilter customGlobalFilter() {
        return (exchange, chain) -> exchange.getPrincipal()
            .map(Principal::getName)
            .defaultIfEmpty("Default User")
            .map(userName -> {
              //adds header to proxied request
              exchange.getRequest().mutate().header("CUSTOM-REQUEST-HEADER", userName).build();
              return exchange;
            })
            .flatMap(chain::filter);
    }
    
    @Bean
    public GlobalFilter customGlobalPostFilter() {
        return (exchange, chain) -> chain.filter(exchange)
            .then(Mono.just(exchange))
            .map(serverWebExchange -> {
              //adds header to response
              serverWebExchange.getResponse().getHeaders().set("CUSTOM-RESPONSE-HEADER",
                  HttpStatus.OK.equals(serverWebExchange.getResponse().getStatusCode()) ? "It worked": "It did not work");
              return serverWebExchange;
            })
            .then();
    }
    

    6 项目使用

    添加依赖:

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

    配置Main启动应用:

    package com.pkslow.cloud.gateway;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class GatewayService {
        public static void main(String[] args) {
            SpringApplication.run(GatewayService.class, args);
        }
    }
    

    配置路由:

    server:
      port: 8080
    spring:
      cloud:
        gateway:
          routes:
          - id: pkslow
            uri: https://www.pkslow.com
            predicates:
            - Path=/pkslow/**
            filters:
            - RewritePath=/pkslow(?<segment>.*), /${segment}
    

    启动后可正常访问了:

    7 总结

    Spring Cloud Gateway实在是非常强大,能满足微服务绝大多数应用场景了,还是很有必要了解一下的。

    代码请查看:https://github.com/LarryDpk/pkslow-samples


    参考资料:官网


    欢迎关注微信公众号<南瓜慢说>,将持续为你更新...

    多读书,多分享;多写作,多整理。

  • 相关阅读:
    Spring源码情操陶冶-AbstractApplicationContext#obtainFreshBeanFactory
    Spring源码情操陶冶-AbstractApplicationContext#prepareRefresh
    Spring源码情操陶冶-AbstractApplicationContext
    Spring源码情操陶冶-ContextLoader
    Spring源码情操陶冶-ContextLoaderListener
    Spring mybatis源码篇章-MapperScannerConfigurer
    Spring mybatis源码篇章-动态SQL节点源码深入
    Spring mybatis源码篇章-动态SQL基础语法以及原理
    Spring mybatis源码篇章-Mybatis的XML文件加载
    Spring mybatis源码篇章-Mybatis主文件加载
  • 原文地址:https://www.cnblogs.com/larrydpk/p/14911107.html
Copyright © 2020-2023  润新知