亲宝软件园·资讯

展开

SpringCloud Gateway的路由,过滤器和限流解读

牧竹子 人气:0

Spring 官方最终还是按捺不住推出了自己的网关组件:Spring Cloud Gateway ,相比之前我们使用的 Zuul(1.x) 它有哪些优势呢?

Zuul(1.x) 基于 Servlet,使用阻塞 API,它不支持任何长连接,如 WebSockets,Spring Cloud Gateway 使用非阻塞 API,支持 WebSockets,支持限流等新特性。

Spring Cloud Gateway

Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

注意:

Spring Cloud Gateway是基于Spring Boot 2.x, Spring WebFlux和Project Reactor 构建的。

因此,在使用Spring Cloud Gateway时,许多不熟悉的同步库(例如,Spring Data和Spring Security)和模式可能不适用。

如果您对这些项目不熟悉,建议您在使用Spring Cloud Gateway之前先阅读它们的文档,以熟悉一些新概念。

Spring Cloud Gateway需要Spring Boot和Spring Webflux提供的Netty运行时。它不能在传统的Servlet容器中或作为WAR构建。

Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。

Spring Cloud Gateway 的特征:

相关概念:

Spring Cloud Gateway 网关路由有两种配置方式:

pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.6.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.SR2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

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

application.yml

server:
  port: 8080
spring:
  cloud:
    gateway:
      routes:
       - id: bamboo_route
        uri: https://blog.csdn.net/
        predicates:
        - Path=/blogdevteam

yml方式配置路由

启动类:代码方式配置路由

package com.bamboo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;

/**
 * @program: spring-gateway
 * @description: Application
 * @author: Bamboo zjcjava@163.com
 * @create: 2019-10-26 20:00
 **/
@SpringBootApplication
public class Application {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                // basic proxy
                .route(r -> r.path("/zjcjava")
                        .uri("https://blog.csdn.net//"))
                .build();
    }

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

}

http://localhost:8080/zjcjava
对应访问的地址是
https://blog.csdn.net/zjcjava

http://localhost:8080/blogdevteam
对应访问的地址是
https://blog.csdn.net/blogdevteam

可以看出来,它会自动在url路径/后面加上对应的路由地址

predicates路由断言工厂

Spring Cloud Gateway将路由作为Spring WebFlux HandlerMapping基础架构的一部分进行匹配。Spring Cloud Gateway包括许多内置的Route Predicate工厂。所有这些谓词都与HTTP请求的不同属性匹配。多个Route Predicate工厂可以合并,也可以通过逻辑合并and。

Predicate 来源于 Java 8,是 Java 8 中引入的一个函数,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。可以用于接口请求参数校验、判断新老数据是否有变化需要进行更新操作。

在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性实现了各种路由匹配规则,有通过 Header、请求参数等不同的条件来进行作为条件匹配到对应的路由。网上有一张图总结了 Spring Cloud 内置的几种 Predicate 的实现。

spring:
  cloud:
    gateway:
        discovery:
          locator:
          enabled: true
          lower-case-service-id: true ##会使用serviceId转发到具体的服务IP上的服务
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
        - Cookie=chocolate, ch.p
        - Header=X-Request-Id, \d+
        - Host=**.somehost.org,**.anotherhost.org
        - Method=GET
        - Path=/foo/{segment},/bar/{segment}
        - Query=baz
        - RemoteAddr=192.168.1.1/24
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

spring.cloud.gateway.discovery.locator.enabled:使用eurake注册服务后:是否与服务发现组件ID进行结合,通过routes中的serviceId 转发到具体的服务实例。

默认为false,设为true便开启通过服务中心的自动根据 serviceId 创建路由的功能。

全局过滤器

该GlobalFilter接口具有与相同的签名GatewayFilter。这些是特殊过滤器,有条件地应用于所有路由。(此界面和用法可能会在将来的里程碑中更改)。

全局过滤器和GatewayFilter的组合订购

当请求进入(并与路由匹配)时,过滤Web处理程序会将的所有实例GlobalFilter和所有特定GatewayFilter于路由的实例添加到过滤器链中。该组合的过滤器链按org.springframework.core.Ordered接口排序,可以通过实现该getOrder()方法进行设置。

由于Spring Cloud Gateway区分了执行过滤器逻辑的“前”阶段和“后”阶段(请参阅:工作原理),因此优先级最高的过滤器将在“前”阶段中处于第一个阶段,而在“后”阶段中处于最后一个阶段“-相。

ExampleConfiguration.java

//放入application启动类中main方法后面即可
@Bean
public CustomGlobalFilter tokenFilter() {
    return new CustomGlobalFilter();
}



/**
 * @program: spring-gateway
 * @description: 全局过滤器
 * @author: Bamboo zjcjava@163.com
 * @create: 2019-10-26 23:06
 **/
public class CustomGlobalFilter implements GlobalFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger(CustomGlobalFilter.class);
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("custom global filter.....................................");
        // 添加全局鉴权
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (token == null || token.isEmpty()) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }

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

这里我创建了一个全局的鉴权过滤器,只有参数中带有token值才能继续,否则提示无权访问

http://localhost:8080/zjcjava?token=aa

fGatewayFilter工厂

路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器适用于特定路由。Spring Cloud Gateway包括许多内置的GatewayFilter工厂。

filters配置

修改配置文件如下:抓哟是 path,filters

server:
  port: 8080
spring:
  application:
    name: spring-cloud-gateway
  cloud:
    gateway:
      routes:
      - id: bamboo_route
        uri: https://blog.csdn.net/
        predicates:
#        - Path=/blogdevteam
        - Path=/test/blogdevteam
        filters:
        - StripPrefix=1 #去掉前缀
        - AddResponseHeader=X-Response-Default-Foo, Default-Bar #返回消息头添加head信息

StripPrefix=1 #去掉第1个前缀以/分割

AddResponseHeader返回报文消息头添加head信息

这里只列举几个重要的过滤器

Hystrix GatewayFilter工厂

Hystrix是Netflix的一个库,用于实现断路器模式。Hystrix GatewayFilter允许您将断路器引入网关路由,保护您的服务免受级联故障的影响,并允许您在下游故障的情况下提供后备响应。

要在项目中启用Hystrix GatewayFilters,请spring-cloud-starter-netflix-hystrix从Spring Cloud Netflix添加依赖项。

Hystrix GatewayFilter工厂需要一个name参数,它是的名称HystrixCommand。

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

这会将其余的过滤器包装在HystrixCommand带有命令名的中myCommandName。

Hystrix过滤器还可以接受可选fallbackUri参数。当前,仅forward:支持计划的URI。如果调用了后备,则请求将被转发到与URI相匹配的控制器。

限流RequestRateLimiter GatewayFilter工厂

RequestRateLimiter GatewayFilter Factory使用一种RateLimiter实现来确定是否允许继续当前请求。如果不是,HTTP 429 - Too Many Requests则返回状态(默认)。

此过滤器采用一个可选keyResolver参数和特定于速率限制器的参数(请参见下文)。

keyResolver是实现KeyResolver接口的bean 。在配置中,使用SpEL按名称引用bean。#{@myKeyResolver}是SpEL表达式,它引用名称为的bean myKeyResolver。

Redis RateLimiter

redis实现基于Stripe所做的工作。它需要使用spring-boot-starter-data-redis-reactiveSpring Boot启动器。

使用的算法是令牌桶算法。

该redis-rate-limiter.replenishRate是多么的每秒许多请求你希望用户被允许做,没有任何下降的请求。这是令牌桶被填充的速率。

redis-rate-limiter.burstCapacity是允许用户在一个单一的第二做请求的最大数目。这是令牌桶可以容纳的令牌数。将此值设置为零将阻止所有请求。

通过在replenishRate和中设置相同的值,可以达到稳定的速率burstCapacity。设置burstCapacity大于可以允许临时爆发replenishRate。在这种情况下,速率限制器需要在突发之间间隔一段时间(根据replenishRate),因为2个连续的突发将导致请求丢失(HTTP 429 - Too Many Requests)。

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10
            redis-rate-limiter.burstCapacity: 20

配置文件

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

这定义了每个用户10的请求速率限制。允许20个并发,但是下一秒只有10个请求可用。这KeyResolver是一个简单的获取user请求参数的参数(注意:不建议在生产中使用)。

速率限制器也可以定义为实现RateLimiter接口的Bean 。在配置中,使用SpEL按名称引用bean。#{@myRateLimiter}是SpEL表达式,它引用名称为的bean myRateLimiter。

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            rate-limiter: "#{@myRateLimiter}"
            key-resolver: "#{@userKeyResolver}"

参考文档

官方参考文档:

https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.0.RC1/reference/html/

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

加载全部内容

相关教程
猜你喜欢
用户评论