Spring Cloud(Kilburn 2022.0.2版本)系列教程(五) 服务网关(SpringCloud Gateway)

news2025/1/9 15:36:43

Spring Cloud(Kilburn 2022.0.2版本)系列教程(五) 服务网关(SpringCloud Gateway)

一、服务网关

1.1 什么是网关

在微服务架构中,服务网关是一个至关重要的组件。它作为系统的入口,负责接收客户端的请求,并将这些请求路由到相应的后端服务。API网关是一个搭建在客户端和微服务之间的服务,可以在API网关中处理一些非业务功能的逻辑,例如权限验证、监控、缓存、请求路由等。API网关就像整个微服务系统的门面一样,是系统对外的唯一入口。有了它,客户端会先将请求发送到API网关,由API网关根据请求的标识信息将请求转发到微服务实例。Spring Cloud GatewaySpring Cloud提供的一个强大的服务网关解决方案。

Spring Cloud Gateway 底层使用了高性能的通信框架Netty。Netty 是高性能中间件的通讯底座, rocketmqseatanacossentinelredissiondubbo 等太多、太多的的大名鼎鼎的中间件,无一例外都是基于netty

Spring Cloud Netflix Zuul 相比,Spring Cloud Gateway具有更好的性能和更丰富的功能。例如,Gateway 基于WebFlux构建,支持响应式编程,能够更好地处理高并发场景。同时,它的路由和过滤配置更加灵活和简洁。Spring Cloud Gateway替换掉Zuul的成本上是非常低的,几乎可以无缝切换。Spring Cloud Gateway几乎包含了Zuul的所有功能。随着时间的发展,Spring Cloud Netflix Zuul会被Spring Cloud Gateway取代,想学点新技术的小伙伴,就去玩转Spring Cloud Gateway吧,别再死死抓住Zuul不放了。

1.2 网关的作用

作用说明
路由接口服务的统一代理,实现前端对接口服务的统一访问。
过滤对用户请求进行拦截、过滤、用户鉴权、监控等。
限流限制用户的访问流量。

1.3 常用的网关

网关名称优点缺点
Spring Cloud Gateway1. 基于 Spring 框架,与 Spring 生态系统集成方便,如和 Spring Boot、Spring Cloud 等配合良好。
2. 支持多种路由匹配方式,包括路径、请求头、请求参数等,灵活性高。
3. 可以方便地通过 Java 代码实现自定义的过滤器,用于实现诸如安全认证、日志记录、请求修改等功能。
4. 具备较好的性能,能处理高并发请求。
1. 对于不熟悉 Spring 框架的开发者有一定的学习成本。
2. 配置相对复杂,尤其是大规模复杂场景下,路由和过滤器的配置可能变得繁琐。
Spring Cloud Netflix Zuul1. 是 Spring Cloud 早期的网关解决方案,和 Spring Cloud 生态融合度较好。
2. 支持动态路由、监控、弹性和安全等功能,能够方便地对请求进行路由和过滤。
3. 可以通过编写 Zuul Filter 来扩展功能。
1. 相比一些新兴的网关,性能在高并发场景下可能稍逊一筹。
2. 新功能更新速度相对较慢,社区活跃度不如一些其他网关。
Kong1. 开源的、轻量级的高性能 API 网关,基于 Nginx 和 OpenResty 构建。
2. 支持插件机制,可以轻松扩展功能,如身份验证、限流、日志记录等。
3. 可用于微服务架构中,对前后端分离的应用进行有效的请求转发和管理。
4. 提供了良好的可扩展性和分布式部署能力。
1. 文档在某些方面可能不够详细,对于初次使用者有一定的学习门槛。
2. 复杂的插件配置可能会影响性能,如果插件使用不当可能出现一些难以排查的问题。
Nginx + Lua1. Nginx 本身性能卓越,处理高并发能力强,可以高效地处理大量的网络请求。
2. Lua 脚本可以方便地嵌入到 Nginx 中实现自定义的业务逻辑,如动态路由、请求过滤等。
3. 可以灵活地进行配置和优化,适用于各种规模的网络架构。
1. 开发和维护需要对 Nginx 和 Lua 都有深入的了解,技术门槛较高。
2. Lua 脚本编写不当可能会导致内存泄漏等问题,影响系统的稳定性。
Traefik1. 自动发现后端服务,支持多种容器编排工具(如 Docker、Kubernetes 等),配置简单。
2. 具有动态配置更新能力,无需重启即可应用新的配置。
3. 提供了简洁直观的 Web UI 用于监控和管理。
4. 性能较好,能有效处理大规模流量。
1. 一些高级功能可能需要额外的配置和学习,对复杂场景的支持可能需要更多探索。
2. 在处理某些特殊的业务逻辑定制方面可能不如一些基于编程实现的网关灵活。

SpringCloud GateWay的主要功能之一是转发请求,转发规则的定义主要包含三大核心概念

术语功能
Route(路由)路由是网关的基本单元,由ID、URI、一组Predicate、一组Filter组成,根据Predicate进行匹配转发。
Predicate(谓语、断言)路由转发的判断条件,目前SpringCloud Gateway支持多种方式,常见如:Path、Query、Method、Header等,写法必须遵循 key=vlue的形式。
Filter(过滤器)过滤器是路由转发请求时所经过的过滤逻辑,可用于修改请求、响应内容。

二、SpringCloud Gateway路由

复制eurekaClient工程,修改名称为hepGatewayEntrance

修改pom.xml文件:

<artifactId>hepGatewayEntrance</artifactId>
<name>hepGatewayEntrance</name>
<description>hepGatewayEntrance</description>

引入以下依赖:

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

修改系统的hostsWindows10hosts文件路径为:C:\Windows\System32\drivers\etc\hostsLinuxmacOS的文件路径为/etc/hosts。增加一行:127.0.0.1 hepGatewayEntrance

2.1 基础URI路由配置

修改application.yml文件为:

server:
  port: 8005 # 端口号

spring:
  main:
    web-application-type: reactive
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: hep-api-userService
          uri: http://localhost:8000
          predicates:
            - Path=/**
  application:
    name: hepGatewayEntrance #Gateway名称

eureka:
  instance:
    prefer-ip-address: false
    hostname: hepGatewayEntrance
    lease-renewal-interval-in-seconds: 5
    lease-expiration-duration-in-seconds: 10
  client:
    healthcheck:
      enabled: true
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://eureka:eurekapwd@eurekaServer:8761/eureka/ 
    registry-fetch-interval-seconds: 5

Spring Cloud Gateway配置各字段含义如下:

  • id:自定义的路由 ID,保持唯一

  • uri:目标服务地址

  • Predicate断言: 这是一个Java 8 Function Predicate。输入类型是Spring Framework ServerWebExchange。允许开发人员匹配来自HTTP请求的任何内容,例如Header或参数。Predicate接受一个输入参数,返回一个布尔值结果。Spring Cloud Gateway内置了许多Predicate,这些Predicate的源码在org.springframework.cloud.gateway.handler.predicate包中。

上面这段配置的意思是,配置了一个 idhep-api-userServiceURI代理规则,路由的规则为:当访问地址http://localhost:8005/getUserById时,会路由到上游地址http://localhost:8000/getUserById

在这里插入图片描述

常见的 Predicate 断言如下

断言示例说明
Path- Path=/user/**当请求路径与 /user/** 匹配时,该请求才能被转发到 http://localhost:8000/ 上。
Before- Before=2024-10-20T11:47:34.255+08:00[Asia/Shanghai]在 2024 年 10 月 20 日 11 时 47 分 34.255 秒之前的请求,才会被转发到 http://localhost:8000/ 上。
After- After=2024-10-20T11:47:34.255+08:00[Asia/Shanghai]在 2024 年 10 月 20 日 11 时 47 分 34.255 秒之后的请求,才会被转发到http://localhost:8000/ 上。
Between- Between=2024-10-20T15:18:33.226+08:00[Asia/Shanghai],2024-10-20T15:23:33.226+08:00[Asia/Shanghai]在 2024 年 10 月 20 日 15 时 18 分 33.226 秒 到 2024年 10 月 20 日 15 时 23 分 33.226 秒之间的请求,才会被转发到http://localhost:8000/服务器上。
Cookie- Cookie=name,c.biancheng.net携带 Cookie 且 Cookie 的内容为 name=c.biancheng.net 的请求,才会被转发到http://localhost:8000/上。
Header- Header=X-Request-Id,\d+请求头上携带属性 X-Request-Id 且属性值为整数的请求,才会被转发到http://localhost:8000/上。
Method- Method=GET只有 GET 请求才会被转发到http://localhost:8000/上。

当然我们也可以把EurekaClient的接口修改一下,使其前面增加一个/user/的路径

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/getUserById")
    public String getUserById() throws Exception{
        return "{id:1,name:jason,age:23,sex: man}";
    }
}

Spring Cloud Gateway中也设置一下/user/路径Path=/user/**

spring:
  main:
    web-application-type: reactive
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: hep-api-userService
          uri: http://localhost:8000
          predicates:
            - Path=/user/**

当访问地址http://localhost:8005/user/getUserById时,会路由到上游地址http://localhost:8000/user/getUserById

在这里插入图片描述

2.2 动态路由配置

Spring Cloud Gateway 会根据Eureka Server服务注册中心中维护的服务列表,以服务名(spring.application.name)作为路径创建动态路由进行转发,从而实现动态路由功能。

我们把Spring Cloud Gatewayuri修改为uri: lb://EUREKACLIENT,其中lb标识负载均衡,为uri的协议,表示开启 Spring Cloud Gateway 的负载均衡功能,EUREKACLIENT是服务的名称,注意一般是大写。

spring:
  main:
    web-application-type: reactive
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: hep-api-userService
          uri: lb://EUREKACLIENT
          predicates:
            - Path=/user/**

三、SpringCloud Gateway 过滤器

3.1 GatewayFilter 网关过滤器

我们来使用一下PrefixPath GatewayFilter吧,当我们增加一项PrefixPath=/user,并把Path中/user/去掉,改成Path=/**

spring:
  main:
    web-application-type: reactive
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: hep-api-userService
          uri: lb://EUREKACLIENT
          predicates:
            - Path=/**
          filters:
            - PrefixPath=/user

所有匹配该路由的请求路径都会被添加/user前缀。例如,一个原本请求/getUserById的请求,经过该过滤器后,实际请求路径会变为/user/getUserById,然后被转发到http://localhost:8000/user/getUserById

在这里插入图片描述

Spring Cloud Gateway 内置了多达 31 种 GatewayFilter,下表中列举了几种常用的网关过滤器及其使用示例。

路由过滤器描述参数使用示例
AddRequestHeader拦截传入的请求,并在请求上添加一个指定的请求头参数。name:需要添加的请求头参数的 key; value:需要添加的请求头参数的 value。- AddRequestHeader=my-request-header,1024
AddRequestParameter拦截传入的请求,并在请求上添加一个指定的请求参数。name:需要添加的请求参数的 key; value:需要添加的请求参数的 value。- AddRequestParameter=my-request-param,c.biancheng.net
AddResponseHeader拦截响应,并在响应上添加一个指定的响应头参数。name:需要添加的响应头的 key; value:需要添加的响应头的 value。- AddResponseHeader=my-response-header,c.biancheng.net
PrefixPath拦截传入的请求,并在请求路径增加一个指定的前缀。prefix:需要增加的路径前缀。- PrefixPath=/consumer
PreserveHostHeader转发请求时,保持客户端的 Host 信息不变,然后将它传递到提供具体服务的微服务中。- PreserveHostHeader
RemoveRequestHeader移除请求头中指定的参数。name:需要移除的请求头的 key。- RemoveRequestHeader=my-request-header
RemoveResponseHeader移除响应头中指定的参数。name:需要移除的响应头。- RemoveResponseHeader=my-response-header
RemoveRequestParameter移除指定的请求参数。name:需要移除的请求参数。- RemoveRequestParameter=my-request-param
RequestSize配置请求体的大小,当请求体过大时,将会返回 413 Payload Too Large。maxSize:请求体的大小。- name: RequestSize args: maxSize: 5000000

31 种 GatewayFilter列表

1. AddRequestHeader 在请求头中添加参数
2. AddRequestParameter 添加请求参数
3. AddResponseHeader
4. The DedupeResponseHeader GatewayFilter Factory
5. The Hystrix GatewayFilter Factory
6. Spring Cloud CircuitBreaker GatewayFilter Factory
7. The FallbackHeaders GatewayFilter Factory
8. The MapRequestHeader GatewayFilter Factory
9. The PrefixPath GatewayFilter Factory
10. The PreserveHostHeader GatewayFilter Factory
11. The RequestRateLimiter GatewayFilter Factory
12. The RedirectTo GatewayFilter Factory
13. The RemoveRequestHeader GatewayFilter Factory
14. RemoveResponseHeader GatewayFilter Factory
15. The RemoveRequestParameter GatewayFilter Factory
16. The RewritePath GatewayFilter Factory
17. RewriteLocationResponseHeader GatewayFilter Factory
18. The RewriteResponseHeader GatewayFilter Factory
19. The SaveSession GatewayFilter Factory
20. The SecureHeaders GatewayFilter Factory
21. The SetPath GatewayFilter Factory
22. The SetRequestHeader GatewayFilter Factory
23. The SetResponseHeader GatewayFilter Factory
24. The SetStatus GatewayFilter Factory
25. The StripPrefix GatewayFilter Factory
26. The Retry GatewayFilter Factory
27. The RequestSize GatewayFilter Factory
28. The SetRequestHostHeader GatewayFilter Factory
29. Modify a Request Body GatewayFilter Factory
30. Modify a Response Body GatewayFilter Factory
31. Default Filters
3.2 GlobalFilter 全局过滤器

GlobalFilter 是一种作用于所有的路由上的全局过滤器,通过它,我们可以实现一些统一化的业务功能,例如权限认证、IP 访问限制等。当某个请求被路由匹配时,那么所有的 GlobalFilter 会和该路由自身配置的 GatewayFilter 组合成一个过滤器链。 GlobalFilter 全局过滤器有Gateway Metrics FilterLocal Response Cache FilterForward Routing FilterNetty Routing FilterNetty Write Response FilterReactiveLoadBalancerClientFilterRouteToRequestUrl FilterWebsocket Routing Filter等。

3.3 GlobalFilter和GatewayFilter的区别

FilteringWebHandler在处理请求时,会将GlobalFilter装饰为GatewayFilter,然后放到同一个过滤器链中,排序以后依次执行。

Spring Cloud Gateway 根据作用范围划分为 GatewayFilterGlobalFilter,二者区别如下:

GatewayFilter:网关过滤器,需要通过 spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过 spring.cloud.default-filters 配置在全局,作用在所有路由上。
GlobalFilter:全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过 GatewayFilterAdapter 包装成 GatewayFilterChain 可识别的过滤器,它为请求业务以及路由的 URI 转换为真实业务服务请求地址的核心过滤器,不需要配置系统初始化时加载,并作用在每个路由上。

四、自定义过滤器

无论是GatewayFilter还是GlobalFilter都支持自定义,只不过编码方式、使用方式略有差别。

4.1 自定义GatewayFilter

自定义GatewayFilter不是直接实现GatewayFilter,而是实现AbstractGatewayFilterFactory。最简单的方式是这样的:

@Component
public class PrintLogGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {
    @Override
    public GatewayFilter apply(Object config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                // 获取请求
                ServerHttpRequest request = exchange.getRequest();
                // 编写过滤器逻辑
                System.out.println("PrintLog executed.");
                // 放行
                return chain.filter(exchange);
            }
        };
    }
}

注意:该类的名称一定要以GatewayFilterFactory为后缀哈。

然后在yaml配置中这样使用:

spring:
  cloud:
    gateway:
      default-filters:
    	- PrintLog # 此处直接以自定义的GatewayFilterFactory类名称前缀类声明过滤器

另外,这种过滤器还可以支持动态配置参数,不过实现起来比较复杂,示例:

@Component
public class PrintLogGatewayFilterFactory // 父类泛型是内部类的Config类型
		extends AbstractGatewayFilterFactory<PrintAnyGatewayFilterFactory.Config> {

    @Override
    public GatewayFilter apply(Config config) {
        // OrderedGatewayFilter是GatewayFilter的子类,包含两个参数:
        // - GatewayFilter:过滤器
        // - int order值:值越小,过滤器执行优先级越高
        return new OrderedGatewayFilter(new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                // 获取config值
                String a = config.getA();
                String b = config.getB();
                String c = config.getC();
                // 编写过滤器逻辑
                System.out.println("a = " + a);
                System.out.println("b = " + b);
                System.out.println("c = " + c);
                // 放行
                return chain.filter(exchange);
            }
        }, 100);
    }

    // 自定义配置属性,成员变量名称很重要,下面会用到
    @Data
    static class Config{
        private String a;
        private String b;
        private String c;
    }
    // 将变量名称依次返回,顺序很重要,将来读取参数时需要按顺序获取
    @Override
    public List<String> shortcutFieldOrder() {
        return List.of("a", "b", "c");
    }
	// 返回当前配置类的类型,也就是内部的Config
    @Override
    public Class<Config> getConfigClass() {
        return Config.class;
    }

}

然后在yaml文件中使用:

spring:
  cloud:
    gateway:
      default-filters:
    	- PrintAny=1,2,3 # 注意,这里多个参数以","隔开,将来会按照shortcutFieldOrder()方法返回的参数顺序依次复制

上面这种配置方式参数必须严格按照shortcutFieldOrder()方法的返回参数名顺序来赋值。

还有一种用法,无需按照这个顺序,就是手动指定参数名:

spring:
  cloud:
    gateway:
      default-filters:
    	- name: PrintAny
    	  args: # 手动指定参数名,无需按照参数顺序
    	    a: 1
    	    b: 2
    	    c: 3
4.2 自定义GlobalFilter

自定义GlobalFilter则简单很多,直接实现GlobalFilter即可,而且也无法设置动态参数:

@Component
public class PrintLogGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 编写过滤器逻辑
        System.out.println("未登录,无法访问");
        // 放行
        // return chain.filter(exchange);

        // 拦截
        ServerHttpResponse response = exchange.getResponse();
        response.setRawStatusCode(401);//设置401无法访问
        return response.setComplete();
    }

    @Override
    public int getOrder() {
        // 过滤器执行顺序,值越小,优先级越高
        return 0;
    }
}

五、SpringCloud Gateway 限流

Gateway是基于令牌桶算法,使用redis作为“桶”结合过滤器实现了网关限流。

pom.xml文件中增加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
5.1 IP限流

为了简便一点,我们就不单独创建一个Configjava类了,直接在启动类中创建一个ipKeyResolver,并指定@Bean(name = "ipKeyResolver")

package cc.huerpu.eurekaclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Objects;

@SpringBootApplication
@EnableDiscoveryClient
public class HepGatewayEntranceApplication {

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

    @Bean(name = "ipKeyResolver")
    public KeyResolver ipKeyResolver() {
        return new KeyResolver() {
            @Override
            public Mono<String> resolve(ServerWebExchange exchange) {
                String hostName = Objects.requireNonNull(exchange.getRequest()
                        .getRemoteAddress()).getHostName();
                System.out.println("hostName:" + hostName);
                return Mono.just(hostName);
            }
        };
    }

}

使用 RequestRateLimiter 过滤器可以实现限流功能。首先需要在配置文件中配置限流规则。在application.yml文件中指定过滤器为RequestRateLimiterkey-resolver用于限流的键的解析器的Bean对象的名字。它使用 SpEL 表达式根据#{@ipKeyResolver}Spring 容器中获取Bean对象,redis-rate-limiter.replenishRate指定令牌桶每s的填充速度,redis-rate-limiter.burstCapacity指定令牌桶容量,redis-rate-limiter.requestedTokens指定每个请求消耗多少个令牌,当然还要配置好redis相关信息。

server:
  port: 8005 # 端口号

spring:
  main:
    web-application-type: reactive
  cloud:
    redis:
      host: 127.0.0.1
      port: 6379
      password: 
      database: 0
    gateway:
      filter:
        request-rate-limiter:
          deny-empty-key: true #如果keyResolver返回空key,则拒绝该请求403,默认true表示拒绝,false则表示允许访问
      discovery:
        locator:
          enabled: true #启用基于服务发现的路由
      routes:
        - id: hep-api-userService
          uri: lb://EUREKACLIENT
          predicates:
            - Path=/**
          filters:
          - name: RequestRateLimiter
            args:
                key-resolver: '#{@ipKeyResolver}'
                redis-rate-limiter.replenishRate: 1 #令牌桶每s的填充速度
                redis-rate-limiter.burstCapacity: 2 #令牌桶容量
                redis-rate-limiter.requestedTokens: 1 #每个请求消耗多少个令牌
          - PrefixPath=/user

  application:
    name: hepGatewayEntrance # Gateway名称

当限流的时候会返回429 Too Many Request,而正当访问会返回正确的结果数据。

在这里插入图片描述

我们使用Postman进行了100次的连续请求,可以看到有成功的,也有429 Too Many Request的,这个限流的表象就跃然纸上了。当我们去Redis服务器查看的时候,也可以看到配置的db0数据库中有限流的相关数据信息。

在这里插入图片描述

5.2 用户限流

根据用户来做限流需要获取当前请求用户的userId,我们在启动类中创建一个userIdResolver,并指定@Bean(name = "userIdResolver")

package cc.huerpu.eurekaclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Objects;

@SpringBootApplication
@EnableDiscoveryClient
public class HepGatewayEntranceApplication {

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

    @Bean(name = "userIdResolver")
    public KeyResolver userKeyResolver() {
        return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getQueryParams().getFirst("userId")));
    }

}

application.yml文件中指定key-resolver: '#{@userIdResolver}'

server:
  port: 8005 # 端口号

spring:
  main:
    web-application-type: reactive
  cloud:
    redis:
      host: 127.0.0.1
      port: 6379
      password: 
      database: 0
    gateway:
      filter:
        request-rate-limiter:
          deny-empty-key: true #如果keyResolver返回空key,则拒绝该请求403,默认true表示拒绝,false则表示允许访问
      discovery:
        locator:
          enabled: true #启用基于服务发现的路由
      routes:
        - id: hep-api-userService
          uri: lb://EUREKACLIENT
          predicates:
            - Path=/**
          filters:
          - name: RequestRateLimiter
            args:
                key-resolver: '#{@userIdResolver}'
                redis-rate-limiter.replenishRate: 1 #令牌桶每s的填充速度
                redis-rate-limiter.burstCapacity: 2 #令牌桶容量
                redis-rate-limiter.requestedTokens: 1 #每个请求消耗多少个令牌
          - PrefixPath=/user

  application:
    name: hepGatewayEntrance # Gateway名称

我们在请求参数中增加userId参数并请求http://localhost:8005/getUserById?userId=1111,可以看到当限流的时候会返回429 Too Many Request,而正当访问会返回正确的结果数据。

在这里插入图片描述

5.3 接口限流

接口限流获取请求地址的uri作为限流的key,我们指定一个名为@Bean(name = "apiKeyResolver")Bean

package cc.huerpu.eurekaclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Objects;

@SpringBootApplication
@EnableDiscoveryClient
public class HepGatewayEntranceApplication {

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


    @Bean(name = "apiKeyResolver")
    public KeyResolver apiKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }

}

application.yml文件中指定key-resolver: '#{@apiKeyResolver}'

server:
  port: 8005 # 端口号

spring:
  main:
    web-application-type: reactive
  cloud:
    redis:
      host: 127.0.0.1
      port: 6379
      password: 
      database: 0
    gateway:
      filter:
        request-rate-limiter:
          deny-empty-key: true #如果keyResolver返回空key,则拒绝该请求403,默认true表示拒绝,false则表示允许访问
      discovery:
        locator:
          enabled: true #启用基于服务发现的路由
      routes:
        - id: hep-api-userService
          uri: lb://EUREKACLIENT
          predicates:
            - Path=/**
          filters:
          - name: RequestRateLimiter
            args:
                key-resolver: '#{@apiKeyResolver}'
                redis-rate-limiter.replenishRate: 1 #令牌桶每s的填充速度
                redis-rate-limiter.burstCapacity: 2 #令牌桶容量
                redis-rate-limiter.requestedTokens: 1 #每个请求消耗多少个令牌
          - PrefixPath=/user

  application:
    name: hepGatewayEntrance # Gateway名称

很简单的,这里就不截图了哈。

Reference:

代码共享地址:https://github.com/jinglisen/SpringCloud-Kilburn-2022/tree/master

Spring Cloud Gateway(Kilburn 2022.0.2版本)官方文档:https://docs.spring.io/spring-cloud-gateway/docs/4.0.9/reference/html/
Spring Cloud Gateway官方文档:https://cloud.spring.io/spring-cloud-gateway/reference/html/

Spring Cloud Gateway中文文档:https://springdoc.cn/spring-cloud-gateway/

SpringCloud-Gateway搭建保姆级教程:https://www.cnblogs.com/sun-10387834/p/17719582.html

SpringCloud Gateway史上最全:https://www.cnblogs.com/crazymakercircle/p/11704077.html

深入探索Spring Cloud Gateway:微服务网关的最佳实践:https://blog.csdn.net/zhengzhaoyang122/article/details/142744233

Spring Cloud Gateway API网关组件,非常详细:https://c.biancheng.net/springcloud/gateway.html

spring cloud gateway 之限流篇:https://www.cnblogs.com/chengmr/p/13277824.html

spring cloud gateway网关使用JMeter进行限流测试与熔断:https://cloud.tencent.com/developer/article/2344888
ring Cloud Gateway官方文档:https://cloud.spring.io/spring-cloud-gateway/reference/html/

Spring Cloud Gateway中文文档:https://springdoc.cn/spring-cloud-gateway/

SpringCloud-Gateway搭建保姆级教程:https://www.cnblogs.com/sun-10387834/p/17719582.html

SpringCloud Gateway史上最全:https://www.cnblogs.com/crazymakercircle/p/11704077.html

深入探索Spring Cloud Gateway:微服务网关的最佳实践:https://blog.csdn.net/zhengzhaoyang122/article/details/142744233

Spring Cloud Gateway API网关组件,非常详细:https://c.biancheng.net/springcloud/gateway.html

spring cloud gateway 之限流篇:https://www.cnblogs.com/chengmr/p/13277824.html

spring cloud gateway网关使用JMeter进行限流测试与熔断:https://cloud.tencent.com/developer/article/2344888

深入学习spring cloud gateway 限流熔断:https://zhuanlan.zhihu.com/p/520347258

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2250481.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于单片机的多功能宠物窝的设计

本设计以STM32主控制器为核心芯片&#xff0c;它的组成元件有电机、温度传感器、时钟模块等。温度传感器的作用是采集环境温度的数据&#xff0c;时钟模块的作用是采集时间。将具体数据进行收集以后&#xff0c;主控制器将所有相关数据予以处理&#xff0c;从而将有关信息传递到…

Windows搭建MaskRCNN环境

环境&#xff1a;python3.6 1. 在miniconda上创建虚拟环境 miniconda下载地址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda # 创建环境 conda create -n maskrcnn python3.6 # 激活 maskrcnn 环境&#xff0c;后续操作都在这个环境下进行 conda ac…

LLM PPT Translator

LLM PPT Translator 引言Github 地址UI PreviewTranslated Result Samples 引言 周末开发了1个PowerPoint文档翻译工具&#xff0c;上传PowerPoint文档&#xff0c;指定想翻译的目标语言&#xff0c;通过LLM的能力将文档翻译成目标语言的文档。 Github 地址 https://github.…

新质驱动·科东软件受邀出席2024智能网联+低空经济暨第二届湾区汽车T9+N闭门会议

为推进广东省加快发展新质生产力&#xff0c;贯彻落实“百县千镇万村高质量发展工程”&#xff0c;推动韶关市新丰县智能网联新能源汽车、低空经济与数字技术的创新与发展&#xff0c;充分发挥湾区汽车产业链头部企业的带动作用。韶关市指导、珠三角湾区智能网联新能源汽车产业…

Zookeeper选举算法与提案处理概览

共识算法(Consensus Algorithm) 共识算法即在分布式系统中节点达成共识的算法&#xff0c;提高系统在分布式环境下的容错性。 依据系统对故障组件的容错能力可分为&#xff1a; 崩溃容错协议(Crash Fault Tolerant, CFT) : 无恶意行为&#xff0c;如进程崩溃&#xff0c;只要…

实例讲解MATLAB绘图坐标轴标签旋转

在进行绘图时需要在图片上添加上做标轴的标签&#xff0c;但是当数据量比较多时&#xff0c;例如一天24小时的数据&#xff0c;这时把每个小时显示在左边轴的标签上&#xff0c;文字内容放不下&#xff0c;因此需要将坐标轴标签旋转一定的角度&#xff0c;这样可以更好在图形上…

flutter项目AndroidiOS自动打包脚本

从业数年余,开发出身,经数载努力位项目经理,因环境欠佳,终失业.失业达七月有余,几经周转,现又从开发,既回原点亦从始.并非与诸位抢食,仅为糊口,望海涵!因从头开始,所经之处皆为新奇,遂处处留痕以备日后之需. 自动打包脚本原文地址:https://zhuanlan.zhihu.com/p/481472311 转…

免费实用在线AI工具集合 - 加菲工具

免费在线工具-加菲工具 https://orcc.online/ sql格式化 https://orcc.online/tools/sql 时间戳转换 https://orcc.online/tools/timestamp Base64 编码解码 https://orcc.online/tools/base64 URL 编码解码 https://orcc.online/tools/url Hash(MD5/SHA1/SHA256…) 计算 h…

Scala学习记录,统计成绩

统计成绩练习 1.计算每个同学的总分和平均分 2.统计每个科目的平均分 3.列出总分前三名和单科前三名&#xff0c;并保存结果到文件中 解题思路如下&#xff1a; 1.读入txt文件&#xff0c;按行读入 2.处理数据 &#xff08;1&#xff09;计算每个同学的总分平均分 import s…

第六届机器人、智能控制与人工智能国际(RICAI 2024)

会议信息 会议时间与地点&#xff1a;2024年12月6-8日&#xff0c;中国南京 会议官网&#xff1a;www.ic-ricai.org &#xff08;点击了解大会参会等详细内容&#xff09; 会议简介 第六届机器人、智能控制与人工智能国际学术会议&#xff08;RICAI 2024&#xff09;将于20…

分布式协同 - 分布式锁一二事儿

文章目录 导图Pre概述概述1. 分布式互斥和临界资源的协调2. 分布式锁的基本原理3. 分布式锁的实现方式a. 基于数据库实现的分布式锁b. 基于Redis实现的分布式锁c. 基于Zookeeper实现的分布式锁 4. 高并发场景下的分布式锁优化a. 分段锁&#xff08;Sharded Locks&#xff09;b.…

Stripe测试

通过官方提供的Stripe-cli工具进行测试。 1. 下载Stripe-cli 下载链接&#xff1a;Release v1.17.1 stripe/stripe-cli GitHub 2. 获取密钥 进入到stripe控制台测试模式 查看API密钥 3. 测试 指定您的API 私钥 stripe login --api-key sk_test_51ISwaXTwNwO1Rvw32DNG10…

Laravel8.5+微信小程序实现京东商城秒杀方案

一、商品秒杀涉及的知识点 鉴权策略封装掊口访问频次限制小程序设计页面防抖接口调用订单创建事务使用超卖防御 二、订单库存系统方案&#xff08;3种&#xff09; 下单减库存 优点是库存和订单的强一致性&#xff0c;商品不会卖超&#xff0c;但是可能导致恶意下单&#xff…

基于单片机设计了居家智能音箱系统(论文+源码)

1系统方案设计 通过需求分析本课题基于单片机的居家智能音箱系统的系统架构如图2.1所示。整个系统采用STM32F103作为控制器&#xff0c;结合LU-ASR01语音识别模块、ESP8266 wifi通信模块、OLED液晶、按键、音乐播放模块、LED灯等构成整个系统。用户可以通过按键、手机APP、语音…

Rook入门:打造云原生Ceph存储的全面学习路径(下)

文章目录 六.Rook部署云原生CephFS文件系统6.1 部署cephfs storageclass6.2 创建容器所需cephfs文件系统6.3创建容器pod使用rook-cephfs提供pvc6.4 查看pod是否使用rook-cephfs 七.Ceph Dashboard界面7.1 启用dashboard开关7.2 ceph-dashboard配置外部访问7.3 Dashboard web ad…

【大数据学习 | Spark-SQL】定义UDF和DUAF,UDTF函数

1. UDF函数&#xff08;用户自定义函数&#xff09; 一般指的是用户自己定义的单行函数。一进一出&#xff0c;函数接受的是一行中的一个或者多个字段值&#xff0c;返回一个值。比如MySQL中的&#xff0c;日期相关的dateDiff函数&#xff0c;字符串相关的substring函数。 先…

vue3 点击按钮,增加和减少input框

需求&#xff1a;手机号的input框默认一个&#xff0c;点击加号&#xff0c;可以增加和减少。 <template><el-form :model"editUserForm" label-width"80px" hide-required-asterisk ref"editUserFormRef"><!-- 手机 --><…

TongRDS分布式内存数据缓存中间件

命令 优势 支持高达10亿级的数据缓冲&#xff0c;内存优化管理&#xff0c;避免GC性能劣化。 高并发系统设计&#xff0c;可充分利用多CPU资源实现并行处理。 数据采用key-value多索引方式存储&#xff0c;字段类型和长度可配置。 支持多台服务并行运行&#xff0c;服务之间可互…

CSP/信奥赛C++语法基础刷题训练(33):洛谷P1055:[NOIP2008 普及组] ISBN 号码

CSP/信奥赛C语法基础刷题训练&#xff08;33&#xff09;&#xff1a;洛谷P1055&#xff1a;[NOIP2008 普及组] ISBN 号码 题目描述 每一本正式出版的图书都有一个 ISBN 号码与之对应&#xff0c;ISBN 码包括 9 9 9 位数字、 1 1 1 位识别码和 3 3 3 位分隔符&#xff0c;其…

算法盒子模型转换步骤+操作命令记录

0、模型转换步骤情 第一步、pt模型转onnx 1) 将要转换的pt模型文件上传到192.168.33.79的 /home/sophonsdk_edge_v1.7_official_release/下 2) 进入docker环境&#xff1a; docker exec -it myname /bin/bash 3) 在workspace目录运行: python3 /usr/local/lib/python3…