从本文开始,笔者将总结 spring cloud 相关内容的教程
版本选择
为了适应 java8,笔者选择了下面的版本,后续会出 java17的以SpringBoot3.0.X为主的教程
SpringBoot 版本 2.6.5
SpringCloud 版本 2021.0.1
SpringCloudAlibaba 版本 2021.0.1.0
SpringCloudAlibaba github 版本说明截图
SpringCloud 官网:https://spring.io/projects/spring-cloud
Spring Cloud Alibaba 官网:https://sca.aliyun.com/zh-cn/
目录
1、环境准备
2、项目创建
3、测试限流
4、改进限流返回
5、项目代码
本文讲解Spring Cloud Gateway 使用 Redis 限流,注册中心使用 Nacos
Macos 官网:https://nacos.io/zh-cn/index.html
Nacos 安装这里不做过多介绍,不了解的朋友可以参考
Nacos 单机安装:https://blog.csdn.net/wsjzzcbq/article/details/123916233
Nacos 集群安装:https://blog.csdn.net/wsjzzcbq/article/details/123956116
笔者使用 docker 开启 nacos 和 redis
Spring Cloud Alibaba 2021.0.1.0 版本对应的nacos版本是 1.4.2
笔者使用的 Naocs 版本是 2.0.0-bugfix,redis 版本是 7.0.6
新建 maven 聚合项目 cloud-learn
最外层父工程 cloud-learn 的 pom.xml
4.0.0
com.wsjzzcbq
cloud-learn
1.0-SNAPSHOT
gateway-learn
consumer-learn
pom
naxus-aliyun
naxus-aliyun
https://maven.aliyun.com/repository/public
true
false
org.springframework.boot
spring-boot-starter-parent
2.6.5
2021.0.1
2021.0.1.0
2021.1
2021.1
3.1.1
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
${spring-cloud-alibaba.version}
pom
import
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
${alibaba-nacos-discovery.veriosn}
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
${alibaba-nacos-config.version}
org.springframework.cloud
spring-cloud-starter-bootstrap
${spring-cloud-starter-bootstrap.version}
com.alibaba.fastjson2
fastjson2
2.0.40
org.projectlombok
lombok
然后创建2个子工程 consumer-learn 和 gateway-learn
gateway-learn 中配置路由转发到 consumer-learn
consumer-learn 工程 pom.xml
cloud-learn
com.wsjzzcbq
1.0-SNAPSHOT
4.0.0
consumer-learn
org.springframework.boot
spring-boot-starter-web
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.cloud
spring-cloud-starter-loadbalancer
org.springframework.boot
spring-boot-maven-plugin
consumer-learn 工程 启动类
package com.wsjzzcbq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* ConsumerApplication
*
* @author wsjz
* @date 2023/09/17
*/
@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
consumer-learn 工程 配置文件
spring.application.name=consumer-learn
server.port=8081
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
spring.cloud.nacos.discovery.server-addr=192.168.31.152:8848
spring.cloud.nacos.discovery.namespace=public
logging.level.com.alibaba.cloudlearnconsumer.feign.ProducerService=DEBUG
consumer-learn 工程 controller
package com.wsjzzcbq.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* ConsumerController
*
* @author wsjz
* @date 2023/09/17
*/
@RestController
public class ConsumerController {
@RequestMapping("/name")
public String user() {
return "宝剑锋从磨砺出,梅花香自苦寒来";
}
}
gateway-learn
gateway-learn 工程 pom.xml
cloud-learn
com.wsjzzcbq
1.0-SNAPSHOT
4.0.0
gateway-learn
org.springframework.cloud
spring-cloud-starter-gateway
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-loadbalancer
org.springframework.boot
spring-boot-starter-data-redis-reactive
com.alibaba.fastjson2
fastjson2
org.springframework.boot
spring-boot-maven-plugin
gateway-learn 工程 启动类
package com.wsjzzcbq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* GatewayApplication
*
* @author wsjz
* @date 2023/09/17
*/
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
限流需要实现 KeyResolver 接口的 resolve 方法
在 resolve 方法中返回限流的维度,如请求路径、ip地址、请求参数等
笔者这里限流维度是请求路径
package com.wsjzzcbq.limit;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* ApiKeyResolver
*
* @author wsjz
* @date 2023/09/17
*/
@Component
public class ApiKeyResolver implements KeyResolver {
@Override
public Mono resolve(ServerWebExchange exchange) {
System.out.println("API限流: " + exchange.getRequest().getPath().value());
return Mono.just(exchange.getRequest().getPath().value());
}
}
gateway-learn 工程 配置文件
server:
port: 9000
spring:
application:
name: gateway-learn
redis:
host: 192.168.31.152
password: 123456
timeout: 5000
database: 0
cloud:
nacos:
discovery:
server-addr: http://192.168.31.152:8848
gateway:
routes:
- id: consumer-learn
uri: lb://consumer-learn
predicates:
- Path=/cloudlearn/consumer/**
filters:
- name: RequestRateLimiter
args:
key-resolver: "#{@apiKeyResolver}"
redis-rate-limiter.replenishRate: 1 #生成令牌速率:个/秒
redis-rate-limiter.burstCapacity: 2 #令牌桶容量
redis-rate-limiter.requestedTokens: 1 #每次消费的Token数量,默认是 1
- StripPrefix=2
配置说明:
RequestRateLimiter 是 gateway 提供的限流过滤器
#{@apiKeyResolver} 是笔者实现的 ApiKeyResolver
redis-rate-limiter.replenishRate 生成令牌的速率每秒几个
redis-rate-limiter.burstCapacity 令牌桶容量
redis-rate-limiter.requestedTokens 每次消费的令牌数量
当请求到网关以 /cloudlearn/consumer/ 为开头前缀时,会路由到 consumer-learn 服务上
创建完成的项目结构
分别启动 consumer-learn 和 gateway-learn
登录 Nacos 控制台查看
启动成功后,可在Naocs 控制台查看注册服务信息
浏览器访问测试限流:http://localhost:9000/cloudlearn/consumer/name
运行效果
可以看到当1秒钟内请求超过2次时会被限流
上面代码实现了限流,但限流触发后返回的是429,不利于前端处理,这里我们可以在默认的限流过滤器基础上进行改进,自定义限流时的返回
新建 NewRequestRateLimiterGatewayFilterFactory 类
继承默认的 RequestRateLimiterGatewayFilterFactory
package com.wsjzzcbq.filter;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.filter.ratelimit.RateLimiter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.HttpStatusHolder;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Map;
/**
* NewRequestRateLimiterGatewayFilterFactory
*
* @author wsjz
* @date 2023/09/17
*/
@Component
public class NewRequestRateLimiterGatewayFilterFactory extends RequestRateLimiterGatewayFilterFactory {
private final RateLimiter defaultRateLimiter;
private final KeyResolver defaultKeyResolver;
private boolean denyEmptyKey = true;
private String emptyKeyStatusCode = HttpStatus.FORBIDDEN.name();
public NewRequestRateLimiterGatewayFilterFactory(RateLimiter defaultRateLimiter, KeyResolver defaultKeyResolver) {
super(defaultRateLimiter, defaultKeyResolver);
this.defaultRateLimiter = defaultRateLimiter;
this.defaultKeyResolver = defaultKeyResolver;
}
@Override
public GatewayFilter apply(Config config) {
System.out.println("过滤限流");
KeyResolver resolver = (KeyResolver)this.getOrDefault(config.getKeyResolver(), this.defaultKeyResolver);
RateLimiter
修改配置文件
配置我们自定义的限流过滤器
server:
port: 9000
spring:
application:
name: gateway-learn
redis:
host: 192.168.31.152
password: 123456
timeout: 5000
database: 0
cloud:
nacos:
discovery:
server-addr: http://192.168.31.152:8848
gateway:
routes:
- id: consumer-learn
uri: lb://consumer-learn
predicates:
- Path=/cloudlearn/consumer/**
filters:
- name: NewRequestRateLimiter
args:
key-resolver: "#{@apiKeyResolver}"
redis-rate-limiter.replenishRate: 1 #生成令牌速率:个/秒
redis-rate-limiter.burstCapacity: 2 #令牌桶容量
redis-rate-limiter.requestedTokens: 1 #每次消费的Token数量
- StripPrefix=2
重新启动 gateway-learn
请求测试
码云地址:https://gitee.com/wsjzzcbq/csdn-blog/tree/master/cloud-learn
至此完