Spring Cloud Gateway使用及配置

18 篇文章 2 订阅

引入依赖包

    <dependencies>
        <!-- gateway核心包 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!-- 基于eureka的功能 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 基于ribbon的功能 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
        <!-- 基于redis的限流功能 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- redis支撑包-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
    </dependencies>

配置文件

Spring相关配置

#应用配置
server:
  port: 8808 #应用端口号
  servlet:
    context-path: /  #应用host名称
spring:
  gateway:
    discovery:
      locator:
        enabled: false # 根据注册中心自动注册路由,默认false 重启生效
        lowerCaseServiceId: false # 将注册表中的服务名转为小写创建路由,默认false,重启生效
    httpclient: #http连接设置
      pool:
        max-connections: 5000 #最大连接数
#       max-life-time: 45000 #最大连接时间
        acquire-timeout: 15000 #返回时间
        max-idle-time: 10000 #最大空闲时间
  application:
        name: lizz-gateway #应用名称
  redis: #redis配置
    database: 6 # Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0
    host: 10.2.55.7   # Redis服务器地址
    port: 6379 # Redis服务器连接端口
    password:  # Redis服务器连接密码(默认为空)
    max-active: 200 # 连接池最大连接数(使用负值表示没有限制)
    max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
    max-idle: 10 # 连接池中的最大空闲连接
    min-idle: 0 # 连接池中的最小空闲连接
    timeout: 1000 # 连接超时时间(毫秒)
#    cluster: 集群
#      nodes:
#        - 127.0.0.1:6379
#        - 127.0.0.1:6380
#        - 127.0.0.1:6381
#        - 127.0.0.1:6382
#eurela注册中心集群地址
eureka:
  instance:
    prefer-ip-address: true #当微服务有使用IP进行注册时,优先使用IP进行访问
  client:
    service-url: 
      defaultZone: http://10.2.55.100:31000/eureka/,http://10.2.55.100:32000/eureka/
#日志级别
logging:
  level:
    org:
      springframework:
        cloud:
          gateway: TRACE #开启跟踪日志用于测试

路由配置

注:

  • “=”号参数不能有空格,如“StripPrefix=1”不能写成“StripPrefix = 1”。
  • 路由匹配从上往下,优先匹配前面的路由。
spring:
  cloud:
    gateway:
        filter:
            remove-hop-by-hop:
              headers:  #默认的移除request中的header
                - aaa
                - bbb
#      httpclient:
#        connect-timeout: 1000 # 转发后端服务超时时间
#        response-timeout: 3s  # 转发后端服务响应超时时间
#      discovery:
#        locator:
#          enabled: true #开启服务注册和发现
#          lower-case-service-id: true #注册名转为小写
      routes: #路由配置
        - id: route_1 #直接跳转到指定域名下 http://10.2.11.6:8808/gw/1 > http://10.2.11.6:8800/gw/1
          uri: http://10.2.11.6:8800 #目标路径
          predicates: #谓词匹配
            - Path=/gw/** #匹配路径
        - id: route_2 #去除前缀跳转 http://10.2.11.6:8808/sp/hi/1 > http://10.2.11.6:8800/hi/1
          uri: http://10.2.11.6:8800 #目标路径
          predicates: #谓词匹配
            - Path=/sp/** #匹配路径
            - Method=GET #指定方式
          filters:
            - StripPrefix=1 #去除第一个级前缀
        - id: route_3 # 增加前缀  http://10.2.11.6:8808/pp/1 > http://10.2.11.6:8800/hi/1
          uri: http://10.2.11.6:8800  #目标路径
          predicates: #谓词匹配
            - Path=/pp/** #匹配路径
          filters:
            - StripPrefix=1 #去除第一个级前缀
            - PrefixPath=/hi #
        - id: route_4 # 重写前缀  http://10.2.11.6:8808/rp/1 > http://10.2.11.6:8800/hi/1
          uri: http://10.2.11.6:8800  #目标路径
          predicates: #谓词匹配
            - Path=/rp/** #匹配路径
          filters:
            - RewritePath=/rp, /hi
        - id: route_5 # 动态重写前缀  http://10.2.11.6:8808/rp1 > http://10.2.11.6:8800/hi/rp1
          uri: http://10.2.11.6:8800  #目标路径
          predicates: #谓词匹配
            - Path=/rp1/** #匹配路径
          filters:
            - RewritePath=(?<oldPath>^/), /hi$\{oldPath}
        - id: route_6 # 指定跳转路径  http://10.2.11.6:8808/setpath > http://10.2.11.6:8800/hi/1
          uri: http://10.2.11.6:8800  #目标路径
          predicates: #谓词匹配
            - Path=/setpath/** #匹配路径
          filters:
            - SetPath=/hi/1
        - id: route_7 # 设置路径,同时使用时,根据前后顺序进行设置,改变顺序结果不同 http://10.2.11.6:8808/allpath > http://10.2.11.6:8800/hi/a
          uri: http://10.2.11.6:8800  #目标路径
          predicates: #谓词匹配
            - Path=/allpath/** #匹配路径
          filters:
            - PrefixPath=/b # http://10.2.11.6:8808/allpath > http://10.2.11.6:8800/b/allpath
            - SetPath=/a # http://10.2.11.6:8800/b/allpath > http://10.2.11.6:8800/a
            - RewritePath=(?<oldPath>^/), /hi$\{oldPath} # http://10.2.11.6:8800/b/a > http://10.2.11.6:8800/hi/a
        - id: route_8 # 通过eureka访问 http://10.2.11.6:8808/eureka/lb/1 > http://10.2.11.6:8800/lb/1
          uri: lb://lizz-eureka-provider  #目标路径
          predicates: #谓词匹配
            - Path=/eureka/** #匹配路径
#          metadata:
#            connect-timeout: 200 #响应时间 ,当前2.2.0版本暂不支持
#            response-timeout: 1000 #链接时间,当前2.2.0版本暂不支持
          filters:
            - StripPrefix=1 #去除第一个级前缀
            - name : RequestSize
              args:
                maxSize: 500000 #限制请求数据大小,byte,比较的长度String contentLength = request.getHeaders().getFirst("content-length");
            - name: Retry #重试过滤器,重试调用lizz-eureka-provider的次数
              args:
                retries: 1 #重试次数 默认3次
                statuses: BAD_GATEWAY #HttpStatus 什么情况下重试,可以是错误码,如:500,502
                series: # HttpStatus.重试系列 默认 SERVER_ERROR-5xx,SUCCESSFUL-2xx ,空为异常补重试,与statuses并行使用
                exceptions:  #异常重试 默认IOException and TimeoutException,空为异常补重试
                methods: GET,POST # HttpMethod 重试的方法 默认 GET GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
                backoff: #延时重试
                  firstBackoff: 10ms #首次延时次数
                  maxBackoff: 50ms # 最大延迟后停止
                  factor: 2 #重试因子 下一次重试延时为firstBackoff*2*n次
                  basedOnPreviousValue: false #为true, backoff 计算公式为 prevBackoff * factor.
        - id: route_9 # 流量限制
          uri: lb://lizz-eureka-provider  #目标路径
          predicates: #谓词匹配
            - Path=/iprate/** #匹配路径
          filters:
            - StripPrefix=1 #去除第一个级前缀
            - name: RequestRateLimiter
              args:
                redis-rate-limiter: #过期时间=burstCapacity/replenishRate*2s
                  replenishRate: 3 #每次补充数量
                  burstCapacity: 1000 #突发容量
                  requestedTokens: 1 #每次请求消耗几个令牌,可以控制不同频率,默认1
                key-resolver: "#{@ipKeyResolver}" # ipKeyResolver 自定义限流柜子
#                rate-limiter: "#{@myRateLimiter}" # 使用自定义限流规则
        - id: route_10 # 修改header
          uri: lb://lizz-eureka-provider  #目标路径
          predicates: #谓词匹配
            - Path=/userrate/** #匹配路径
          filters:
            - AddRequestHeader=X-Request-Foo,Bar #增加转发请求的header 格式:key,value
            - AddRequestParameter=foo,bar #增加转发请求的参数
            - AddResponseHeader=X-Request-Foo,Bar #增加返回数据的header
            - RemoveRequestHeader=X-Request-Foo #移除转发请求的header
            - RemoveResponseHeader=X-Request-Foo #移除返回数据的header
            

Ribbon相关配置

ribbon:
  eureka:
    enabled: true #默认开启ribbon,关闭fasle
spring:
  cloud:
    loadbalancer:
      retry:
        enabled: true #开启
VEHICLE-CUSTOMER-SERVICE: #对应lb的微服务名称
  ribbon:
    #BestAvailableRule:选择一个最小的并发请求的server
    #AvailabilityFilteringRule:过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值)
    #WeightedResponseTimeRule:根据响应时间分配一个weight,响应时间越长,weight越小,被选中的可能性越低。
    #RetryRule:对选定的负载均衡策略机上重试机制。
    #RoundRobinRule:roundRobin方式轮询选择server
    #RandomRule:随机选择一个server
    #ZoneAvoidanceRule:复合判断server所在区域的性能和server的可用性选择server
#    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #负载策略,默认RoundRobinRule轮训策略
    NFLoadBalancerRuleClassName: com.gateway.loadbalancer.MatchRule #自定义负载策略
    #listOfServers: localhost:8090,localhost:9092,localhost:9999 #自定义服务列表,不使用eureka,需要ribbon.eureka.enabled设置为false
    #ServerListRefreshInterval: 10000 #listOfServers列表刷新时间,单位ms
#    ReadTimeout: 1 # 请求处理的超时时间
#    ConnectTimeout: 1 # 请求连接的超时时间
#    OkToRetryOnAllOperations: false # 对所有操作请求都进行重试,默认 false
#    MaxAutoRetriesNextServer: 1 #切换重试次数
#    MaxAutoRetries: 3 #对当前实例的重试次数

限流规则代码

方法名与配置文件中的key-resolver参数对应

@Configuration
public class RateResolver {

    @Value("")
    /**
     * 必须有一个主键方法
     * 根据ip进行限流
     * @return
     */
    @Primary
    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
    /**
     * 根据用户限流
     * 根据参数中的userId值进行限流
     * @return
     */
    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
    }
    /**
     * 根据api限流
     * 根据请求path进行限流
     * @return
     */
    @Bean
    KeyResolver apiKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }

    /**
     * 根据自定义key限流
     * @return
     */
    @Bean
    public KeyResolver otherKeyResolver() {
        return exchange -> Mono.just(getOtherKey(exchange));
    }
    /**
     * 自定义限流key,根据需要生产key
     * @param exchange
     * @return
     */
    private String getOtherKey(ServerWebExchange exchange){
        String key;
        String userId = exchange.getRequest().getQueryParams().getFirst("uid");
        Map aa = exchange.getAttributes();
        key = userId + aa.get("group");
        return key;
    }

}

限流原理

执行限流过程时,Gateway会通过在request_rate_limiter.lua脚本在redis中创建两个key:

  • request_rate_limiter.{$key}.timestamp:最近获取令牌时间
  • request_rate_limiter.{$key}.tokens:可用令牌数量

注:key的存活时间为路由配置中的 burstCapacity/replenishRate*2s

当burstCapacity:100,replenishRate:2,100/2*2s=100s

当burstCapacity:200,replenishRate:100,200/100*2s=4s

正常情况几秒内就会消失,需要查看key值可以将差值调大查看。

自定义过滤器

公用过滤器

实现GlobalFilter和Ordered即可。

/**
 * @Description: 自定义拦截器
 * @Auther: lizz
 * @Date: 2019/12/26 17:32
 */
@Component
public class JWTFilter implements GlobalFilter, Ordered {
    private static final Logger logger = LoggerFactory.getLogger(JWTFilter.class);
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        logger.info(" JWTFilter 过滤");
        //获取请求信息进行过滤
//        exchange.getApplicationContext();
//        exchange.getAttribute("uid");
//        exchange.getAttributes();
//        exchange.getFormData();
//        exchange.getRequest().getQueryParams();
//        exchange.getSession();
        //拦截请求
        //return exchange.getResponse().setComplete();
        //执行下一个拦截器
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        //拦截器优先级,0位最先执行
        return 0;
    }
}

 

  • 1
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lizz666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值