您现在的位置是:首页 >其他 >Spring Cloud Gateway使用及原理解析网站首页其他

Spring Cloud Gateway使用及原理解析

kse_music 2024-06-17 11:26:57
简介Spring Cloud Gateway使用及原理解析


前言

随着人Zuul2的不断跳票,Spring官方推出高性能网关Spring Cloud Gateway,使用Netty通信,reactor反应式框架编程。本文就介绍了该网关的基础内容以及进阶使用。讲解版本3.1.4对应SpringCloud版本2021.0.5

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

一、路由(Route)

Route主要作用就是做请求的转发,而在转发前可以对路由进行断言(判断请求是否被该路由处理)、过滤。

1.定义(RouteDefinition)

一个路由至少需要定义一个uri和一个断言,例如:定义一个处理所有请求以/web开头的请求

#lb://开头代表是服务负载均衡转发请求,如果是转发到指定地址也可以写成http://localhost:8081
spring.cloud.gateway.routes[0].uri=lb://web
#Path表示使用的是PathRoutePredicateFactory生成的GatewayPredicate,处理以/web开头的所有请求
spring.cloud.gateway.routes[0].predicates[0]=Path=/web/**
#Path表示使用的是StripPrefixGatewayFilterFactory生成的GatewayFilter,会将接口请求路径的第一部分过滤掉
# 如请求http://localhost:8802/web/user/list则实际访问的是lb://web/user/list
spring.cloud.gateway.routes[0].filters[0]=StripPrefix=1

提示:断言和过滤器的定义底层解析规则都是一样的即一个名字name(String)和一组参数args(Map<String,String>),像上面的配置方式则会将Path=/web/**以逗号分隔,Path给name,/web/**给args的value,key为内部自动生成_genkey_0(数字0代表下标),如果是拦截多个路径可以写成Path=/web/**,/web2/**,则/web2/**给到args的key就为_genkey_1。这是一种快键的配置方式。我们也可以使用下面标准的配置方式

spring.cloud.gateway.routes[0].uri=lb://web
spring.cloud.gateway.routes[0].predicates[0].name=Path
spring.cloud.gateway.routes[0].predicates[0].args[patterns][0]=/web/**
spring.cloud.gateway.routes[0].filters[0]=StripPrefix=1

2.加载(RouteDefinitionRouteLocator)

将RouteDefinition加载成Route,在1中的示例会生成一个具有一个断言一个过滤器的路由,

提示:如果定义了默认过滤器也会被加载,后面还会专门讲到

二、断言

1.内置断言

  1. AfterRoutePredicateFactory
  2. BeforeRoutePredicateFactory
  3. BeforeRoutePredicateFactory
  4. BetweenRoutePredicateFactory
  5. CookieRoutePredicateFactory
  6. HeaderRoutePredicateFactory
  7. HostRoutePredicateFactory
  8. MethodRoutePredicateFactory
  9. PathRoutePredicateFactory
  10. QueryRoutePredicateFactory
  11. ReadBodyRoutePredicateFactory
  12. RemoteAddrRoutePredicateFactory
  13. XForwardedRemoteAddrRoutePredicateFactory
  14. CloudFoundryRouteServiceRoutePredicateFactory

2.关闭/启用

#关闭After断言对应AfterRoutePredicateFactory
spring.cloud.gateway.predicate.after.enabled=false
#启用AfterRoutePredicateFactory(默认就是启用的)
spring.cloud.gateway.predicate.after.enabled=true

#关闭RemoteAddr断言对应RemoteAddrRoutePredicateFactory
spring.cloud.gateway.predicate.remote-addr.enabled=false

3.自定义

三、过滤器

有三类过滤器,其中全局过滤器GlobalFilter和默认过滤器都是对所有路由生效,区别是全局过滤器只需要定义一个实现GlobalFilter接口的bean就可以了,默认过滤器除了要定义一个实现GatewayFilterFactory接口的Bean之外还需要通过spring.cloud.gateway.default-filters配置启用,普通GatewayFilter需要在定义路由时一个个配置启用。

1.内置GlobalFilter

  1. RemoveCachedBodyFilter
  2. AdaptCachedBodyGlobalFilter
  3. NettyWriteResponseFilter
  4. GatewayMetricsFilter
  5. RouteToRequestUrlFilter
  6. ReactiveLoadBalancerClientFilter
  7. LoadBalancerServiceInstanceCookieFilter
  8. WebsocketRoutingFilter
  9. NettyRoutingFilter
  10. ForwardRoutingFilter

以上仅是默认启用的

2.默认过滤器

#配置一个默认断路过滤器
spring.cloud.gateway.default-filters[0].name=CircuitBreaker
spring.cloud.gateway.default-filters[0].args[fallbackUri]=forward:/fallback

3.GatewayFilter

  1. AddRequestHeaderGatewayFilterFactory
  2. MapRequestHeaderGatewayFilterFactory
  3. AddRequestParameterGatewayFilterFactory
  4. AddResponseHeaderGatewayFilterFactory
  5. ModifyRequestBodyGatewayFilterFactory
  6. DedupeResponseHeaderGatewayFilterFactory
  7. ModifyResponseBodyGatewayFilterFactory
  8. CacheRequestBodyGatewayFilterFactory
  9. PrefixPathGatewayFilterFactory
  10. PreserveHostHeaderGatewayFilterFactory
  11. RedirectToGatewayFilterFactory
  12. RemoveRequestHeaderGatewayFilterFactory
  13. RemoveRequestParameterGatewayFilterFactory
  14. RemoveResponseHeaderGatewayFilterFactory
  15. RequestRateLimiterGatewayFilterFactory
  16. RewritePathGatewayFilterFactory
  17. RetryGatewayFilterFactory
  18. SetPathGatewayFilterFactory
  19. SecureHeadersGatewayFilterFactory
  20. SetRequestHeaderGatewayFilterFactory
  21. SetRequestHostHeaderGatewayFilterFactory
  22. SetResponseHeaderGatewayFilterFactory
  23. RewriteResponseHeaderGatewayFilterFactory
  24. RewriteLocationResponseHeaderGatewayFilterFactory
  25. SetStatusGatewayFilterFactory
  26. SaveSessionGatewayFilterFactory
  27. StripPrefixGatewayFilterFactory
  28. RequestHeaderToRequestUriGatewayFilterFactory
  29. RequestSizeGatewayFilterFactory
  30. RequestHeaderSizeGatewayFilterFactory

三类过滤器在执行时都会被包装成GatewayFilter去执行,执行顺序是通过AnnotationAwareOrderComparator排序的即先通过是否实现Ordered接口再通过是否有@Order注解。其中需要注意的是GlobalFilter需要指定实现Ordered接口,不能使用注解@Order,github已经有许多人提了该issue

4.关闭/启用

#关闭AdaptCachedBodyGlobalFilter过滤器
spring.cloud.gateway.global-filter.adapt-cached-body.enabled=false

#关闭AddRequestHeader过滤器对应AddRequestHeaderGatewayFilterFactory
spring.cloud.gateway.filter.add-request-header.enabled=false

5.自定义

  1. 自定义一个全局过滤器MyGlobalFilter
@Component
public class MyGlobalFilter implements GlobalFilter{

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (ObjectUtils.isEmpty(token)) {
            return ServerHttpResponseUtils.failed("无token",exchange.getResponse());
        }
        return chain.filter(exchange);
    }

}
  1. 自定义一个普通过滤器CustomGatewayFilterFactory
@Component
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config> {

    private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";
    private static final String KEY = "withParams";

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

    public CustomGatewayFilterFactory() {
        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());
                            }
                            System.out.println(sb);
                        }
                    })
            );
        };
    }

    public static class Config {

        private boolean withParams;

        public boolean isWithParams() {
            return withParams;
        }

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

}

四、熔断&限流

1.熔断


#定义一个默认配置名为base,超时时间为40s
resilience4j.timelimiter.configs.base.timeout-duration=40s
#定义微服务名web的断路超时时间为50s,若不指定时间则使用base配置中的40s
resilience4j.timelimiter.instances.web.base-config=base
resilience4j.timelimiter.instances.web.timeout-duration=50s

#配置一个默认断路过滤器
spring.cloud.gateway.default-filters[0].name=CircuitBreaker
spring.cloud.gateway.default-filters[0].args[fallbackUri]=forward:/fallback

2.限流

spring.cloud.gateway.routes[1].uri=lb://reactive-web
spring.cloud.gateway.routes[1].predicates[0]=Path=/reactive/**
spring.cloud.gateway.routes[1].predicates[1]=After=2019-04-20T17:42:47.789-07:00[America/Denver]

spring.cloud.gateway.routes[1].filters[0].name=RequestRateLimiter
spring.cloud.gateway.routes[1].filters[0].args[key-resolver]=#{@hostAddressKeyResolver}
spring.cloud.gateway.routes[1].filters[0].args[redis-rate-limiter.replenishRate]=1
spring.cloud.gateway.routes[1].filters[0].args[redis-rate-limiter.burstCapacity]=3

自定义一个key解析器

@Component
public class HostAddressKeyResolver implements KeyResolver {

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

}

五、集成Nacos

1.依赖

   <dependency>
       <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2021.0.5.0</version>
    </dependency>

2.路由加载

服务发现是通过DiscoveryClientRouteDefinitionLocator加载路由的,默认会加载服务注册中心中所有的服务

#排除网关自身作为路由
spring.cloud.gateway.discovery.locator.include-expression=!serviceId.equals('gateway')

总结

以上就是今天要讲的内容,本文详细介绍了Spring Cloud Gateway的使用,而Spring Cloud Gateway提供了大量能使我们快速便捷地处理路由的函数和方法。

完整代码

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。