Gateway的过滤器,断言,限流

依赖:
<dependencies>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
        </dependency>

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

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>


    </dependencies>

 application.yml文件

server:
  port: 7000
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: order_route #当前路由标识,要求唯一
          uri: lb://shop-orders #从nacos中获取服务
          order: 1 #路由优先规则,数字越小级别越高
          predicates: #断言 路由转发的时候需要满足条件
           - Path=/order-ser/** #请求路径要满足这个条件
           - Before=2023-07-29T00:00:00.000+08:00[Asia/Shanghai] #限制请求时间在 2023-07-23之前
           - Method=GET #限制请求方式为get
           - Age=20,70
          filters: #过滤器 请求之前传递过程中我们可以通过过滤器进行路径修改
           - StripPrefix=1 #转发之前去掉一层路径
        - id: product_route #当前路由标识,要求唯一
          uri: lb://shop-product #从nacos中获取服务
          order: 1 #路由优先规则,数字越小级别越高
          predicates: #断言 路由转发的时候需要满足条件
           - Path=/product-ser/** #请求路径要满足这个条件
          filters: #过滤器 请求之前传递过程中我们可以通过过滤器进行路径修改
           - StripPrefix=1 #转发之前去掉一层路径
           - SetStatus=20000 #修改的是返回的状态   # Result  code==200 msg data
           - Log=true,false # 控制日志是否打开
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

一.过滤器

1.局部过滤器

                                    自定义 局部过滤器【只作用于一个过滤器】 
                                          自己配置一个 Log日志的过滤器 

第一步  : yml中进行设置日志是否打开 
                 - Log=true,false # 控制日志是否打开 

第二步 :配置 静态内部类 
                @Data
                @NoArgsConstructor
                public static class Config{
                            private boolean consoleLog;
                            private boolean cacheLog;
                }

第三步: 自定义一个过滤器工厂,实现方法 
          @Override
          public GatewayFilter apply(LogGatewayFilterFactory.Config config) {

          @Override
          public List<String> shortcutFieldOrder() {

          添加一个无参数的构造   
          里面使用 super(LogGatewayFilterFactory.config.class);  

第四步 :测试 

@Component
public class LogGatewayFilterFactory extends AbstractGatewayFilterFactory<LogGatewayFilterFactory.config> {


    public LogGatewayFilterFactory() {
        super(LogGatewayFilterFactory.config.class);
    }

    @Override
    public GatewayFilter apply(LogGatewayFilterFactory.config config) {

        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

                if(config.isConsoleLog()){
                    System.out.println("ConsoleLog-已经开启了.....");
                }

                if(config.isCacheLog()){
                    System.out.println("CacheLog+已经开启了....");
                }
                
                return chain.filter(exchange);//这个过滤器执行完毕了,移交给下一个过滤器
            }
        };
    }
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("consoleLog","cacheLog");
    }

    @Data
    @NoArgsConstructor
    public static class config{

        private boolean consoleLog;
        private boolean cacheLog;
    }
}

2.全局过滤器

全局过滤器 
  作用于所有的路由,无需配置。通过全局过滤器可以实现 权限的统一校验、安全性功能校验。

 
 SpringCloud提供了一系列的全局过滤器 !【内置的全局过滤器 】
  LoadBalancerClientFilter

  WebsocketRoutingFilter 
  
  WebClientHttpRoutingFilter

  WebClientWriteResponseFilter

  RouteToRequestUrlFilter


  自定义全局过滤器 : 完成权限校验

  开发中的鉴权逻辑:
    1.当客户端第一次进行请求的时候,服务器对用户进行信息认证(登录)
    2.认证通过,将用户的信息进行加密形成token,返回给客户端,作为登录凭证
    3.每次请求的过程中,客户端都需要携带认证的token 
    4.服务器需要对token进行解密,判断是否有效 

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token=exchange.getRequest().getQueryParams().getFirst("token");
        if (!StringUtils.equals(token,"admin")){

            System.out.println("鉴权失败");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);//未经授权的

            return exchange.getResponse().setComplete();//完成了
        }
        return chain.filter(exchange);
    }


    /**
     * 顺序  数值越小,优先级别越高
     * @return
     */

    @Override
    public int getOrder() {
        return 0;
    }
}

二.断言

限制年龄场景:
   假设我们让年龄在20--70之间的人群是可以进入直播间进行刷礼物 !(min,max)

   步骤如下:
    第一步 需要在配置文件中添加一个关于Age的断言 
      predicates: #断言 路由转发的时候需要满足的条件
            - Path=/product-ser/**  #请求路径要满足这个需求
            - Before=2023-07-29T00:00:00.000+08:00[Asia/Shanghai] #限制请求时间在 2023-07-23之前
            - Method=GET #限制请求方式为get
            - Age=20,70 #限制20岁到70岁的人群可以访问   --》就是它 

   第二步:开发自定义断言类 
   public class AgeRoutePredicateFactory extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {

   第三步:
      添加静态内部类 
          @Data
    @NoArgsConstructor
    public static class Config{
        private int minAge;
        private int maxAge;

    }

  第四步:
     重写两个方法

         /**
     *  读取配置文件中的参数
     * @return
     */
    @Override
    public List<String> shortcutFieldOrder() {
     

    /**
     * 断言的逻辑
     * @param config
     * @return
     */
    @Override
    public Predicate<ServerWebExchange> apply(AgeRoutePredicateFactory.Config config) {

 第五步: 测试 

@Component
public class AgeRoutePredicateFactory extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config>  {

    public AgeRoutePredicateFactory() {
        super(AgeRoutePredicateFactory.Config.class);
    }

    /**
     *  读取配置文件中的参数
     * @return
     */
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("minAge","maxAge");
    }

    /**
     * 断言的逻辑
     * @param config
     * @return
     */
    @Override
    public Predicate<ServerWebExchange> apply(AgeRoutePredicateFactory.Config config) {

        return new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                //接收前台传递过来的age
                String strAge = serverWebExchange.getRequest().getQueryParams().getFirst("age");

                if(!StringUtils.isEmpty(strAge)){
                    int age = Integer.parseInt(strAge);
                    if(age<config.getMaxAge() && age>config.getMinAge()){
                        return true;
                    }else{
                        return  false;
                    }
                }
                return false;
            }
        };
    }

    @Data
    @NoArgsConstructor
    public static class Config{
        private int minAge;
        private int maxAge;

    }
}

三.限流

 使用网关进行限流 

   第一步: 添加依赖 
           <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
        </dependency>

@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolvers;
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    //初始化限流过滤器

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter(){
        return new SentinelGatewayFilter();
    }


    //配置初始化的限流参数
    @PostConstruct
    public void initGatewayRules(){
        Set<GatewayFlowRule> rules=new HashSet<>();
        //添加咱们资源名  对应的是路由id   //统计时间窗口 单位是秒
        rules.add(new GatewayFlowRule("product_route").setCount(1).setIntervalSec(1));
        //加入网关
        GatewayRuleManager.loadRules(rules);
    }

    //配置限流异常处理接口
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(){
        return new SentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);
    }

    //自定义一个处理异常的界面
    @PostConstruct
    public void initBlockExceptionHandler(){

        BlockRequestHandler blockRequestHandler=new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                Map map=new HashMap<>();
                map.put("code",500012);
                map.put("message","接口被限流了");

                return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8).body(BodyInserters.fromObject(map));
            }
        };
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值