zoukankan      html  css  js  c++  java
  • 45

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

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

    特性
    Spring Cloud Gateway 具有如下特性:

    基于Spring Framework 5, Project Reactor 和 Spring Boot 2.0 进行构建;
    动态路由:能够匹配任何请求属性;
    可以对路由指定 Predicate(断言)和 Filter(过滤器);
    集成Hystrix的断路器功能;
    集成 Spring Cloud 服务发现功能;
    易于编写的 Predicate(断言)和 Filter(过滤器);
    请求限流功能;
    支持路径重写。
    实战 Gateway
    引入 gateway
    新建jlw-gateway项目

    引入gateway依赖

    org.springframework.cloud spring-cloud-starter-gateway 加入Eureka注册中心

    开启服务注册和发现

    gateway 服务端口

    server:
    port: 9000

    spring:
    cloud:
    gateway:
    discovery:
    locator:
    # 启用DiscoveryClient网关集成的标志
    enabled: true
    # 服务小写匹配
    lower-case-service-id: true
    配置完上面,Gateway 就可以自动根据服务发现为每个服务创建router了,然后将已服务名开头的请求路径转发到对应的服务。

    Gateway Actuator API
    pom中引入spring-boot-starter-actuator相关依赖,然后配置文件添加如下代码,开启gateway相关的端点。

    management:
    endpoints:
    web:
    exposure:
    #应该包含的端点ID,全部:*
    include: ‘gateway’
    重启项目,访问http://localhost:9000/actuator/gateway/routes就可以查看到配置的路由信息了

    更多gateway路由信息接口展示如下图:

    相关概念
    Route(路由):
    路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由;
    Predicate(断言):
    指的是Java 8 的 Function Predicate。 输入类型是Spring框架中的ServerWebExchange。 这使开发人员可以匹配HTTP请求中的所有内容,例如请求头或请求参数。如果请求与断言相匹配,则进行路由;
    Filter(过滤器):
    指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前后对请求进行修改。
    路由基本配置
    Gateway 提供了两种不同的方式用于配置路由:一种是通过yml文件来配置,另一种是通过Java Bean来配置

    ①使用配置文件

    spring:
    cloud:
    gateway:
    routes:
    - id: eureka-provider
    uri: lb://eureka-provider
    predicates:
    - Path=/api/ep/**
    filters:
    - StripPrefix=2
    字段含义解释:

    id
    我们自定义的路由 ID,保持唯一
    uri
    目标服务地址,大部分场景我们是转发到某个服务上,配置lb://eureka-provider意思是请求要转发到注册中心的eureka-provider服务上。
    predicates
    路由条件,接受一个参数,返回一个布尔结果决定是否匹配。Gateway 为我们内置了多种路由条件,包括 Path、Cookie、Param、Header、Before、After 等等,开箱即用,当然我们也可以自己实现 predicates
    filters
    过滤规则,当请求经过 predicate 匹配成功后,执行 filter,我们可以使用它修改请求和响应,示例表示目标服务收到的 path 将会忽略2位路径path。
    ②使用Java Bean配置

    配置RouteLocator对象,代码示例如下:

    @Bean
    public RouteLocator customRoutes(RouteLocatorBuilder builder){
    return builder.routes()
    // 请求网关路径包含 /api/ec/** 的都会被路由到eureka-client
    .route(“eureka-client”,r->r.path("/api/ec/")
    .filters(f->f.stripPrefix(2))
    .uri(“lb://eureka-client”))
    // 可以配置多个route
    .route(“eureka-client2”,r->r.path("/api/ec2/")
    .filters(f->f.stripPrefix(2))
    .uri(“lb://eureka-client”))
    .build();
    }
    以上配置后,通过http://localhost:9000/api/ec/sayHello 或者http://localhost:9000/api/ec2/sayHello 都会被路由到eureka-client服务。

    路由规则:Predicate
    Spring Cloud Gateway 内置了很多 Predicates 工厂(可以通过访问路径/actuator/gateway/routepredicates查看),这些 Predicates 工厂通过不同的 HTTP 请求参数来匹配,多个 Predicates 工厂可以组合使用。

    按照其功能可以大致分为以下几种不同 Predicate

    1.通过请求时间匹配路由
    在指定时间之后的请求会匹配该路由:AfterRoutePredicateFactory

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    predicates:
    - After=2019-10-10T00:00:00+08:00[Asia/Shanghai]
    在指定时间之前的请求会匹配该路由:BeforeRoutePredicateFactory

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    predicates:
    - Before=2019-10-10T00:00:00+08:00[Asia/Shanghai]
    在指定时间区间内的请求会匹配该路由:BetweenRoutePredicateFactory

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    predicates:
    - Between=2019-10-01T00:00:00+08:00[Asia/Shanghai], 2019-10-10T00:00:00+08:00[Asia/Shanghai]
    2.通过Cookie匹配路由
    Cookie Route Predicate 可以接收两个参数,一个是 Cookie name,一个是正则表达式。示例如下:

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    predicates:
    - Cookie=name, jinglingwang.cn
    3.通过 Header匹配路由
    Header Route Predicate 和 Cookie Route Predicate 一样,也是接收 2 个参数,一个 header 中属性名称和一个正则表达式,示例如下:

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    predicates:
    - Header=name, jinglingwang.cn
    4.通过 Host 匹配路由
    该模式接收一个参数:主机列表,示例如下:

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    predicates:
    - Host=.jinglingwang.cn,.jinglingwang.com
    5.通过 Request Method 匹配路由
    可以通过是 POST、GET、PUT、DELETE 等不同的请求方式来进行路由,示例代码如下:

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    predicates:
    - Method=GET,POST
    6.通过请求路径匹配路由
    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    predicates:
    - Path=/api/rc/**
    7.通过请求参数匹配路由
    该模式有两个参数:一个必需的param和一个可选的regexp(Java正则表达式),示例如下

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    predicates:
    - QUERY=name,jingling*
    8.通过指定远程地址匹配路由
    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    predicates:
    - RemoteAddr=192.168.1.1/24 #192.168.1.1是IP 24是子网掩码
    如果请求的远程地址是192.168.1.10,则此路由匹配。

    9.通过权重来匹配路由
    该模式有两个参数:group和Weight(一个int值),示例如下:

    spring:
    cloud:
    gateway:
    routes:
    - id: weight_high
    uri: http://localhost:8201
    predicates:
    - Weight=group1, 8
    - id: weight_low
    uri: http://localhost:8202
    predicates:
    - Weight=group1, 2
    以上表示有80%的请求会被路由到localhost:8201,20%会被路由到localhost:8202

    网关过滤器
    路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器只能指定路由进行使用。Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生。

    添加请求Header过滤器

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    filters:
    - AddRequestHeader=source, jinglingwang.cn
    上面的示例会为所有匹配的请求向下游请求时在Header中添加source=jinglingwang.cn

    添加请求参数过滤器

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    filters:
    - AddRequestParameter=source, jinglingwang.cn
    上面的示例会把source=jinglingwang.cn添加到下游的请求参数中

    添加响应头过滤器

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    filters:
    - AddResponseHeader=source, jinglingwang.cn
    上面的示例会把source=jinglingwang.cn添加到所有匹配请求的下游响应头中。

    剔除重复的响应头过滤器

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    filters:
    - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
    DedupeResponseHeader过滤器也可接收可选策略参数,可接收参数值包括:RETAIN_FIRST (默认值,保留第一个值), RETAIN_LAST(保留最后一个值), and RETAIN_UNIQUE(保留所有唯一值,以它们第一次出现的顺序保留)。

    开启Hystrix断路器功能的过滤器

    要开启断路器功能,我们需要在pom.xml中添加Hystrix的相关依赖:spring-cloud-starter-netflix-hystrix

    然后添加相关服务降级的处理类:

    @RestController
    public class FallbackController{
    @GetMapping("/fallback")
    public Object fallback() {

        Map<String,Object> result = new HashMap<>(3);
        result.put("data","jinglingwang.cn");
        result.put("message","Get request fallback!");
        result.put("code",500);
        return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    }
    添加配置

    spring:
    cloud:
    gateway:
    routes:
    - id: eureka-provider
    uri: lb://eureka-provider
    predicates:
    - Path=/api/ep/**
    filters:
    - StripPrefix=2
    - name: Hystrix
    args:
    name: fallbackcmd
    fallbackUri: forward:/fallback
    启用resilience4j断路器的过滤器

    要启用Spring Cloud断路器过滤器,需要引入依赖spring-cloud-starter-circuitbreaker-reactor-resilience4j

    spring:
    cloud:
    gateway:
    routes:
    - id: ribbon-client
    uri: lb://ribbon-client
    filters:
    - CircuitBreaker=myCircuitBreaker
    还可以接受一个可选的fallbackUri参数:

    spring:
    cloud:
    gateway:
    routes:
    - id: eureka-provider
    uri: lb://eureka-provider
    predicates:
    - Path=/api/ep/**
    filters:
    - StripPrefix=2
    - name: CircuitBreaker
    args:
    name: myCircuitBreaker
    fallbackUri: forward:/fallback
    关闭eureka-provider服务,访问http://localhost:9000/api/ep/hello接口,出现降级处理信息

    上面的配置也可以用JAVA Bean的方式配置:

    @Bean
    public RouteLocator customRoutes(RouteLocatorBuilder builder){
    return builder.routes()
    .route(“eureka-provider”, r -> r.path("/api/ep/**")
    .filters(f->f.stripPrefix(2).circuitBreaker(c->c.setName(“myCircuitBreaker”).setFallbackUri(“forward:/fallback”)))
    .uri(“lb://eureka-provider”))
    .build();
    }
    6.1 根据状态码使断路器跳闸

    根据返回的状态码,决定断路器是否要跳闸

    spring:
    cloud:
    gateway:
    routes:
    - id: eureka-provider
    uri: lb://eureka-provider
    predicates:
    - Path=/api/ep/**
    filters:
    - StripPrefix=2
    - name: CircuitBreaker
    args:
    name: myCircuitBreaker
    fallbackUri: forward:/fallback
    statusCodes:
    - 500
    - ‘NOT_FOUND’
    或者JAVA Bean配置:

    @Bean
    public RouteLocator customRoutes(RouteLocatorBuilder builder){
    return builder.routes()
    .route(“eureka-provider”, r -> r.path("/api/ep/**")
    .filters(f->f.stripPrefix(2).circuitBreaker(c->c.setName(“myCircuitBreaker”).setFallbackUri(“forward:/fallback”).addStatusCode(“500”)))
    .uri(“lb://eureka-provider”))
    .build();
    }
    其中NOT_FOUND是HttpStatus枚举的String表示形式

    增加路径的过滤器

    spring:
    cloud:
    gateway:
    routes:
    - id: eureka-provider
    uri: lb://eureka-provider
    predicates:
    - Path=/api/ep/**
    filters:
    - PrefixPath=/mypath
    把/mypath作为所有匹配请求路径的前缀

    去掉路径前缀的过滤器

    spring:
    cloud:
    gateway:
    routes:
    - id: eureka-provider
    uri: lb://eureka-provider
    predicates:
    - Path=/api/ep/**
    filters:
    - StripPrefix=2
    以上配置会忽略两位路径path,当访问网关API /api/ep/hello 时,向eureka-provider发起/hello请求

    用于限流的过滤器

    RequestRateLimiter 过滤器可以用于限流,RateLimiter实现来确定是否允许继续当前请求。 如果不是,则返回HTTP 429—太多请求(默认)的状态。

    该过滤器采用可选的keyResolver参数和速率限制器特定的参数,keyResolver是一个实现KeyResolver接口的bean。在配置中,使用SpEL按名称引用bean。#{@myKeyResolver}是引用名为myKeyResolver的bean的SpEL表达式。

    使用 Redis RateLimiter

    引入redis依赖,配置好redis。

    org.springframework.boot spring-boot-starter-data-redis-reactive 添加配置,使用的算法是令牌桶算法。

    spring:
    cloud:
    gateway:
    routes:
    - id: eureka-provider
    uri: lb://eureka-provider
    predicates:
    - Path=/api/ep/**
    filters:
    - name: RequestRateLimiter
    args:
    redis-rate-limiter.replenishRate: 10 #允许用户每秒处理多少个请求,而不丢弃任何请求。这是令牌桶的填充速率
    redis-rate-limiter.burstCapacity: 20 #一个用户在一秒钟内允许做的最大请求数。这是令牌桶可以容纳的令牌数。将该值设置为零会阻止所有请求。
    redis-rate-limiter.requestedTokens: 1 #一个请求花费多少令牌
    通过在“replenishRate”和“burstCapacity”中设置相同的值来实现稳定的速率。通过将burstCapacity设置为高于replenishRate,可以允许临时爆发。

    配置KeyResolver

    JAVA 代码:

    @Configuration
    public class RedisRateLimiterConfig{
    @Bean
    KeyResolver userKeyResolver() {
    // 根据请求参数中的phone进行限流
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst(“phone”));
    }
    @Bean
    @Primary
    public KeyResolver ipKeyResolver() {
    // 根据访问IP进行限流
    return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
    }
    配置RequestRateLimiter

    spring:
    cloud:
    gateway:
    routes:
    - id: eureka-provider
    uri: lb://eureka-provider
    predicates:
    - Path=/api/ep/**
    filters:
    - name: RequestRateLimiter
    args:
    redis-rate-limiter.replenishRate: 1 #允许用户每秒处理多少个请求,而不丢弃任何请求。这是令牌桶的填充速率
    redis-rate-limiter.burstCapacity: 2 #一个用户在一秒钟内允许做的最大请求数。这是令牌桶可以容纳的令牌数。将该值设置为零会阻止所有请求。
    redis-rate-limiter.requestedTokens: 1 #一个请求花费多少令牌
    key-resolver: “#{@ipKeyResolver}”
    多次请求,会返回状态码为429的错误

    用于重定向的过滤器

    spring:
    cloud:
    gateway:
    routes:
    - id: eureka-provider
    uri: lb://eureka-provider
    predicates:
    - Path=/api/ep/**
    filters:
    - StripPrefix=2
    - RedirectTo=302, https://jinglingwang.cn #302 重定向到https://jinglingwang.cn
    效果图如下:

    用于重试的过滤器

    spring:
    cloud:
    gateway:
    routes:
    - id: eureka-provider
    uri: lb://eureka-provider
    predicates:
    - Path=/api/ep/**
    filters:
    - StripPrefix=2
    - name: Retry
    args:
    retries: 3
    statuses: BAD_GATEWAY
    methods: GET,POST
    backoff:
    firstBackoff: 10ms
    maxBackoff: 50ms
    factor: 2
    basedOnPreviousValue: false
    参数解释:

    retries:应该尝试的重试次数。
    statuses:应该重试的HTTP状态代码,HttpStatus。
    methods:应该重试的HTTP方法,HttpMethod。
    series:要重试的状态码,Series。
    exceptions:应该重试的引发异常的列表。
    backoff:为重试配置的指数补偿
    用于限制请求大小的过滤器

    spring:
    cloud:
    gateway:
    routes:
    - id: eureka-provider
    uri: lb://eureka-provider
    predicates:
    - Path=/api/ep/**
    filters:
    - StripPrefix=2
    - name: RequestSize
    args:
    maxSize: 5MB
    当请求大小大于允许的限制时,网关会限制请求到达下游服务。maxSize参数后跟一个可选的数据单位,如“KB节”或“MB”,默认是“B”。

    上面的配置如果超过限制会出现以下提示:

    errorMessage:Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB

    配置http超时时间
    我们可以为所有路由配置Http超时(响应和连接),并且为每个特定路由配置单独的超时时间

    全局的超时时间配置:

    spring:
    cloud:
    gateway:
    httpclient:
    connect-timeout: 1000
    response-timeout: 5s
    特定路由配置超时时间

    spring:
    cloud:
    gateway:
    routes:
    - id: eureka-provider
    uri: lb://eureka-provider
    predicates:
    - Path=/api/ep/**
    metadata:
    response-timeout: 2000
    connect-timeout: 1000
    或者使用JAVA Bean的方式配置:

    @Bean
    public RouteLocator customRoutes(RouteLocatorBuilder builder){
    return builder.routes()
    .route(“eureka-provider”, r -> r.path("/api/ep/")
    .filters(f->f.stripPrefix(2)
    .requestRateLimiter(rate->rate.setKeyResolver(ipKeyResolver))
    .circuitBreaker(c->c.setName(“myCircuitBreaker”).setFallbackUri(“forward:/fallback”).addStatusCode(“500”).addStatusCode(“NOT_FOUND”)))
    .uri(“lb://eureka-provider”)
    .metadata(RESPONSE_TIMEOUT_ATTR, 200)
    .metadata(CONNECT_TIMEOUT_ATTR, 200))
    .build();
    }
    跨域配置
    spring:
    cloud:
    gateway:
    globalcors: # 全局跨域配置
    cors-configurations:
    '[/]’:
    allowedOrigins: “jinglingwang.cn”
    allowedMethods:
    - GET
    add-to-simple-url-handler-mapping: true
    上面的配置,对于所有Get请求,允许来自jinglingwang.cn的跨域请求。

    自定义 Route Predicate Factories
    通过一个名为AbstractRoutePredicateFactory的抽象类来进行扩展,示例代码:

    public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {

    public MyRoutePredicateFactory(){
        super(Config.class);
    }
    
    @Override
    public Predicate<ServerWebExchange> apply(Config config){
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                String host = exchange.getRequest().getHeaders().getFirst("Host");
                return "jinglingwang.cn".equalsIgnoreCase(host);
            }
    
            @Override
            public String toString() {
                return String.format("host: name=%s ", config.host);
            }
        };
    }
    
    public static class Config {
        //自定义过滤器的配置属性
        @NotEmpty
        private String host;
    }
    

    }
    自定义 GatewayFilter Factories
    要写GatewayFilter,必须实现GatewayFilterFactory,可以通过扩展一个名为AbstractGatewayFilterFactory的抽象类来进行。

    @Component
    public class AddHeaderGatewayFilterFactory extends AbstractGatewayFilterFactory<AddHeaderGatewayFilterFactory.Config>{

    public AddHeaderGatewayFilterFactory() {
        super(Config.class);
    }
    @Override
    public GatewayFilter apply(Config config){
        return (exchange, chain) -> {
            // 如果要构建“前置”过滤器,则需要在调用chain.filter之前处理
            ServerHttpRequest request = exchange.getRequest().mutate()
                    .header("source", "jinglingwang.cn").build();
            //使用构建器来处理请求
            return chain.filter(exchange.mutate().request(request).build());
        };
    }
    
    public static class Config {
        //Put the configuration properties for your filter here
    }

    }

  • 相关阅读:
    高斯消元学习
    HDU 4596 Yet another end of the world(解一阶不定方程)
    Codeforces Round #318 div2
    HDU 4463 Outlets(一条边固定的最小生成树)
    HDU 4458 Shoot the Airplane(计算几何 判断点是否在n边形内)
    HDU 4112 Break the Chocolate(简单的数学推导)
    HDU 4111 Alice and Bob (博弈)
    POJ 2481 Cows(线段树单点更新)
    HDU 4288 Coder(STL水过)
    zoj 2563 Long Dominoes
  • 原文地址:https://www.cnblogs.com/gd11/p/14217141.html
Copyright © 2011-2022 走看看