注意:本片文章的示例是在《Spring Cloud Alibaba入门十二:Spring Cloud Gateway的使用》的基础上进行的.下面直接上步骤:
1. 添加Sentinel依赖
编辑pom.xml文件,新增以下内容:
<!-- 3.引入sentinel对gateway的支持 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>
2. 添加Gateway配置文件
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
}
3. 新增一个自启动类
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
public class SentinelApplicationRunner implements ApplicationRunner {
public void run(ApplicationArguments args) throws Exception {
initGatewayRules();
}
/**
* 配置Gateway限流规则
*/
public void initGatewayRules() {
GatewayFlowRule gatewayFlowRule = new GatewayFlowRule();
gatewayFlowRule.setResource("qfx-product") // 路由ID
.setCount(1) // 限流阈值
.setIntervalSec(1); // 统计时间窗口,单位是秒,默认是1秒
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(gatewayFlowRule);
GatewayRuleManager.loadRules(rules);
}
}
4. 测试
启动项目,访问地址并快速刷新,可以看到限流已经生效
5. 返回自定义提示
上面的测试中返回的是默认的提示信息,我们可以自定义返回提示
5.1 重写SentinelGatewayBlockExceptionHandler
import java.nio.charset.StandardCharsets;
import java.util.List;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler;
import reactor.core.publisher.Mono;
public class MySentinelGatewayBlockExceptionHandler implements WebExceptionHandler {
public MySentinelGatewayBlockExceptionHandler(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
}
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpResponse serverHttpResponse = exchange.getResponse();
serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
byte[] datas = "{\"code\":403,\"msg\":\"API接口被限流\"}".getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(datas);
return serverHttpResponse.writeWith(Mono.just(buffer));
}
}
5.2 重新编辑自启动类
编辑GatewayConfiguration.java,修改或添加以下内容:
(Ordered.HIGHEST_PRECEDENCE)
public MySentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// 自定义的限流异常处理类.
return new MySentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
自启动类GatewayConfiguration.java修改后的完整代码如下:
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.qfx.common.handler.MySentinelGatewayBlockExceptionHandler;
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
// @Bean
// @Order(Ordered.HIGHEST_PRECEDENCE)
// public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// // Register the block exception handler for Spring Cloud Gateway.
// return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
// }
(Ordered.HIGHEST_PRECEDENCE)
public MySentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// 自定义的限流异常处理类.
return new MySentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
}
5.3 测试
再次启动项目,访问地址并快速刷新,可以看到限流已经生效,并返回自定义提示信息
6. 动态配置
可以把自启动中的限流规则放到数据库或者Nacos中,这里就不再详细说明了