百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

SpringCloud Gateway 应用Hystrix 限流功能 自定义Filter详解

toyiye 2024-06-21 19:08 9 浏览 0 评论

环境:Springboot2.3.10.RELEASE + SpringCloud Hoxton.SR11 + SpringCloud Alibaba2.2.5.RELEASE + Redis


依赖

<dependencies>
  <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
  </dependency>
</dependencies>
  • 工程机构
  • service-consumer子模块接口
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
	
  @Resource
  private RestTemplate restTemplate ;
  @Resource
  private HttpServletRequest request ;
	
  @GetMapping("/get")
  public Object invoke(String serviceName) {
    try {
      TimeUnit.SECONDS.sleep(3) ;
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return restTemplate.getForObject("http://service-producer/discovery/get?serviceName=" + serviceName, Object.class);
  }
	
}
  • service-producer子模块接口
@RestController
@RequestMapping("discovery")
public class DiscoveryController {

  @NacosInjected
  private NamingService namingService;
  @Resource
  private DiscoveryClient discoverClient ;

  @GetMapping(value = "/get")
  public Object get(@RequestParam String serviceName) throws Exception {
    Map<String, Object> res = new HashMap<>() ;
    res.put("services", discoverClient.getServices()) ;
    res.put("instances", discoverClient.getInstances(serviceName)) ;
    res.put("port", 9000) ;
    return res  ;
  }
}

服务发现配置(访问中直接服务名访问)

方式一(不推荐):

spring:
  cloud:
    gateway:
      discovery:
        locator:
          # 如:http://localhost:9999/service-consumer/consumer/get?serviceName=service-producer
          enabled: true 
          lower-case-service-id: true

通过上面的配置,我们可以直接通过服务名(spring.application.name)来访问服务。实际在生产环境应该不会这样用吧,所以这样的功能应该是关闭的。

访问:

方式二:

spring:
  cloud:
    gateway:
      routes:
      - id: gw001
        #当前如果配置的路由被匹配,这里的uri就是被转发的地址
        uri: lb://service-consumer
        # 这里的name(Path)是GatewayPredicate接口实现类对应的前缀。如:PathRoutePredicateFactory => Path
        predicates:
        #下面两种写法都OK。XXX=xxx  这种写法与谓词工厂中的shortcutFieldOrder方法是对应的Pattern是List集合,那么多个配置就用逗号分割。
        - Path=/api/**, /api-a/**, /api-b/**
        filters:
        #截取请求路径的第一段(http://xxx:port/api/demo) 这里会自动的截取掉/api  
        #最后的转发地址为:  http://service-consumer/demo          
        - StripPrefix=1

访问:

这里可以分别通过/api, /api-a, /api-b三个前缀访问。

整合Hystrix

这里需要引入Hystrix依赖

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
spring:
  cloud:
    gateway:
      routes:
      - id: gw001
        #当前如果配置的路由被匹配,这里的uri就是被转发的地址
        uri: lb://service-consumer
        # 这里的name(Path)是GatewayPredicate接口实现类对应的前缀。如:PathRoutePredicateFactory => Path
        predicates:
        #下面两种写法都OK。XXX=xxx  这种写法与谓词工厂中的shortcutFieldOrder方法是对应的Pattern是List集合,那么多个配置就用逗号分割。
        - Path=/api/**, /api-a/**, /api-b/**
        filters:
        - StripPrefix=1
        - name: Hystrix
          args:
            name: gatewayfallback
            fallbackUri: forward:/gateway/error

注意:Hystrix Filter的name必须填写,名称随意。fallbackUri属性是在降级的时候调用的接口。

@RestController
@RequestMapping("/gateway")
public class DefaultController {
	
  @RequestMapping("/error")
  public Object error() {
    Map<String, Object> result = new HashMap<>() ;
    result.put("code", -1) ;
    result.put("message", "服务不可用,请稍候再试") ;
    result.put("data", null) ;
    return result ;
  }
	
}

hysrix默认的熔断时间是1s,所以在service-consumer接口中通过睡眠3s来模拟

访问:

hysrix相关的配置还是按照常规的配置即可。

自定义过滤器

  • 全局过滤器
@Component
public class GlobalExecutionTimeFilter implements GlobalFilter {

  private static Logger logger = LoggerFactory.getLogger(GlobalExecutionTimeFilter.class) ;
	
  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		
    long start = System.currentTimeMillis() ;
		
    Mono<Void> result = chain.filter(exchange) ;
		
    logger.info("本次任务执行时间:{}", (System.currentTimeMillis() - start) + "毫秒") ;
    return result ;
  }

}

只需要实现GlobalFilter并且注册成Bean即可。全局过滤器会自动的应用到所有的路由上并且还不同配置任何东西。

访问:

  • 自定义路由过滤器

该过滤器必须配置到具体的路由才能生效。

下面自定义一个验证token的过滤器。

@Component
public class TokenGatewayFilterFactory extends AbstractGatewayFilterFactory<TokenGatewayFilterFactory.TokenConfig> {
  public static final String ENABLE_KEY = "enable";
  public static final String EXCLUDE_KEY = "exclude" ;

  public TokenGatewayFilterFactory() {
    super(TokenConfig.class);
  }
	
  @Override
  public List<String> shortcutFieldOrder() {
    return Arrays.asList(ENABLE_KEY, EXCLUDE_KEY);
  }

	@Override
	public GatewayFilter apply(TokenConfig config) {
    return (exchange, chain) -> {
      if (!config.isEnable()) {
        return chain.filter(exchange) ;
      }
      ServerHttpRequest request = exchange.getRequest() ;
      ServerHttpResponse response = exchange.getResponse() ;
      String token = request.getHeaders().getFirst("access-token") ;
      if (token == null || "".equals(token)) {
        token = request.getQueryParams().getFirst("access-token") ;
      }
      if (token == null || "".equals(token)) {
        DataBuffer data = setErrorInfo(response, "请检查Token是否填写");
        return response.writeWith(Mono.just(data)) ;
      }
      return chain.filter(exchange) ;
    };
	}

	private DataBuffer setErrorInfo(ServerHttpResponse response, String msg) {
    //设置headers
    HttpHeaders httpHeaders = response.getHeaders();
    httpHeaders.add("Content-Type", "application/json; charset=UTF-8");
    httpHeaders.add("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
    //设置body
    String body = "{\"code\":-1, \"message\": \"" + msg + "\"}";
    DataBuffer data = response.bufferFactory().wrap(body.getBytes());
    return data;
  }
	
	public static class TokenConfig {
    private boolean enable ;
    private String exclude ;

    public String getExclude() {
      return exclude;
    }

    public void setExclude(String exclude) {
      this.exclude = exclude;
    }

    public boolean isEnable() {
      return enable;
    }

    public void setEnable(boolean enable) {
      this.enable = enable;
    }
  }
	
}

配置:

spring:
  cloud:
    gateway:
      routes:
      - id: gw001
        #当前如果配置的路由被匹配,这里的uri就是被转发的地址
        uri: lb://service-consumer
        # 这里的name(Path)是GatewayPredicate接口实现类对应的前缀。如:PathRoutePredicateFactory => Path
        predicates:
        #下面两种写法都OK。XXX=xxx  这种写法与谓词工厂中的shortcutFieldOrder方法是对应的Pattern是List集合,那么多个配置就用逗号分割。
        - Path=/api/**, /api-a/**, /api-b/**
        filters:
        - StripPrefix=1
        - name: Hystrix
          args:
            name: gatewayfallback
            fallbackUri: forward:/gateway/error
        - name: Token
          args:
            enable: true

访问:

如果请求header中不包含access-token

限流

引入依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
</dependency>
spring:
  cloud:
    gateway:
      routes:
      - id: gw001
        #当前如果配置的路由被匹配,这里的uri就是被转发的地址
        uri: lb://service-consumer
        # 这里的name(Path)是GatewayPredicate接口实现类对应的前缀。如:PathRoutePredicateFactory => Path
        predicates:
        #下面两种写法都OK。XXX=xxx  这种写法与谓词工厂中的shortcutFieldOrder方法是对应的Pattern是List集合,那么多个配置就用逗号分割。
        - Path=/api/**, /api-a/**, /api-b/**
        filters:
        - StripPrefix=1
        - name: RequestRateLimiter
          args:
            keyResolver: '#{@redisKeyResolver}' #SpringEL表达式
            redis-rate-limiter.replenishRate: 1 #补充率,每秒产生多少令牌
            redis-rate-limiter.burstCapacity: 2 #令牌桶容量
@Component
public class RedisKeyResolver implements KeyResolver {

  // 限流策略,根据IP等信息进行限流,同一IP每秒访问次数
  @Override
  public Mono<String> resolve(ServerWebExchange exchange) {
    String address = exchange.getRequest().getRemoteAddress().getHostString() ;
    return Mono.just(address) ;
  }

}

访问:

当访问过快就会返回429状态码,太多的请求。

完毕!!!

给个关注+转发呗谢谢

关注公众:Springboot实战案例锦集

Spring Cloud Sentinel 熔断降级

Spring Cloud Sentinel 流控限流

Spring Cloud Sentinel 基础配置

Spring Cloud Nacos 开启权限验证

Spring Cloud Gateway应用详解1之谓词

SpringCloud Nacos 整合feign

SpringCloud Alibaba 之 Nacos 服务

Spring Cloud Sentinel整合Feign

SpringCloud Nacos 服务提供者

SpringCloud Nacos 服务动态配置

SpringCloud zuul 动态网关配置

Spring Cloud Gateway应用详解2内置过滤器

SpringCloud Hystrix实现资源隔离应用

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码