赞
踩
一,应用场景:开放平台提供url给第三方调用时,针对调用方请求进行限流,实现对ip和参数进行限流
两种实现方式
1,对SentinelGatewayBlockExceptionHandler进行改造,新创建一个该类,重写里面的返回方法
可参考:http://www.cppcns.com/ruanjian/java/257764.html
@Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { // Register the block exception handler for Spring Cloud Gateway. return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer); }
2,平台实现,自定义响应处理类,实现BlockRequestHandler接口,包装返回信息,初始化调用自定义响应处理类
参考:https://blog.csdn.net/developlee/article/details/100987345
您可以在 GatewayCallbackManager
注册回调进行定制:
setBlockHandler
:注册函数用于实现自定义的逻辑处理被限流的请求,对应接口为 BlockRequestHandler
。默认实现为 DefaultBlockRequestHandler
,当被限流时会返回类似于下面的错误信息:Blocked by Sentinel: FlowException
。
二,代码实现,改造SentinelGatewayBlockExceptionHandler
1,Sentinel配置类
- /**
- * sentinel配置
- *
- * @author lr
- * @date 2019-09-12 13:31
- */
- @Configuration
- public class SentinelGatewayConfiguration {
-
- @Autowired
- private InetUtils inetUtils;
-
- private final List<ViewResolver> viewResolvers;
- private final ServerCodecConfigurer serverCodecConfigurer;
-
- public SentinelGatewayConfiguration(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);
- // }
-
- /**
- * 自定义响应参数
- *
- * @return
- */
- @Bean
- @Order(Ordered.HIGHEST_PRECEDENCE)
- public JsonSentinelGatewayBlockExceptionHandler jsonSentinelGatewayBlockExceptionHandler() {
- return new JsonSentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
- }
-
- @Bean
- @Order(-1)
- public GlobalFilter sentinelGatewayFilter() {
- return new SentinelGatewayFilter();
- }
-
- @PostConstruct
- public void doInit() {
- initGatewayRules();
- //GatewayCallbackManager.setBlockHandler(new OpenBlockRequestHandler());
- //设置监控ip(多网卡时默认获取有问题,所以需要采用springCloud网卡工具类)
- SentinelConfig.setConfig(TransportConfig.HEARTBEAT_CLIENT_IP, inetUtils.findFirstNonLoopbackAddress().getHostAddress());
- }
-
- /**
- * 初始化路由规则
- */
- private void initGatewayRules() {
- Set<GatewayFlowRule> rules = new HashSet<>();
-
- //限制每个ip每秒只能调用5次,
- //setBurst突发请求额外增加5个
- rules.add(new GatewayFlowRule("open_gateway")
- .setCount(5)
- .setIntervalSec(1)
- .setBurst(5)
- .setParamItem(new GatewayParamFlowItem()
- .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_CLIENT_IP)
- )
- );
-
- //限制一个应用appId每秒只能调用5次
- //setBurst突发请求额外增加5个
- rules.add(new GatewayFlowRule("open_gateway")
- .setCount(5)
- .setIntervalSec(1)
- .setBurst(5)
- .setParamItem(new GatewayParamFlowItem()
- .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
- .setFieldName("appId")
- )
- );
-
- //限制一个应用appId每秒只能调用5次
- //setBurst突发请求额外增加5个
- rules.add(new GatewayFlowRule("open_gateway")
- .setCount(5)
- .setIntervalSec(1)
- .setBurst(5)
- .setParamItem(new GatewayParamFlowItem()
- .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
- .setFieldName("appId").setPattern("testApp")
- )
- );
-
- GatewayRuleManager.loadRules(rules);
- }
- }
2,自定义响应类
- public class JsonSentinelGatewayBlockExceptionHandler implements WebExceptionHandler {
-
- private List<ViewResolver> viewResolvers;
- private List<HttpMessageWriter<?>> messageWriters;
- private final Supplier<ServerResponse.Context> contextSupplier = () -> {
- return new ServerResponse.Context() {
- public List<HttpMessageWriter<?>> messageWriters() {
- return JsonSentinelGatewayBlockExceptionHandler.this.messageWriters;
- }
-
- public List<ViewResolver> viewResolvers() {
- return JsonSentinelGatewayBlockExceptionHandler.this.viewResolvers;
- }
- };
- };
-
- public JsonSentinelGatewayBlockExceptionHandler(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
- this.viewResolvers = viewResolvers;
- this.messageWriters = serverCodecConfigurer.getWriters();
- }
-
- private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
- ServerHttpResponse serverHttpResponse = exchange.getResponse();
- serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
- JSONObject responseObj = new JSONObject();
- responseObj.put("code", 403);
- responseObj.put("msg", "请求过于频繁,请稍后重试");
- byte[] datas = responseObj.toString().getBytes(StandardCharsets.UTF_8);
- DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(datas);
- return serverHttpResponse.writeWith(Mono.just(buffer));
- }
-
- public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
- if (exchange.getResponse().isCommitted()) {
- return Mono.error(ex);
- } else {
- return !BlockException.isBlockException(ex) ? Mono.error(ex) : this.handleBlockedRequest(exchange, ex).flatMap((response) -> {
- return this.writeResponse(response, exchange);
- });
- }
- }
-
- private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
- return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
- }
-
- }
三,代码实现,GatewayCallbackManager
回调
1,Sentinel配置类
- /**
- * sentinel配置
- *
- * @author lr
- * @date 2019-09-12 13:31
- */
- @Configuration
- public class SentinelGatewayConfiguration {
-
- @Autowired
- private InetUtils inetUtils;
-
- private final List<ViewResolver> viewResolvers;
- private final ServerCodecConfigurer serverCodecConfigurer;
-
- public SentinelGatewayConfiguration(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);
- }
-
- /**
- * 自定义响应参数
- *
- * @return
- */
- // @Bean
- // @Order(Ordered.HIGHEST_PRECEDENCE)
- // public JsonSentinelGatewayBlockExceptionHandler jsonSentinelGatewayBlockExceptionHandler() {
- // return new JsonSentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
- // }
-
- @Bean
- @Order(-1)
- public GlobalFilter sentinelGatewayFilter() {
- return new SentinelGatewayFilter();
- }
-
- @PostConstruct
- public void doInit() {
- initGatewayRules();
- GatewayCallbackManager.setBlockHandler(new OpenBlockRequestHandler());
- //设置监控ip(多网卡时默认获取有问题,所以需要采用springCloud网卡工具类)
- SentinelConfig.setConfig(TransportConfig.HEARTBEAT_CLIENT_IP, inetUtils.findFirstNonLoopbackAddress().getHostAddress());
- }
-
- /**
- * 初始化路由规则
- */
- private void initGatewayRules() {
- Set<GatewayFlowRule> rules = new HashSet<>();
-
- //限制每个ip每秒只能调用5次,
- //setBurst突发请求额外增加5个
- rules.add(new GatewayFlowRule("open_gateway")
- .setCount(5)
- .setIntervalSec(1)
- .setBurst(5)
- .setParamItem(new GatewayParamFlowItem()
- .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_CLIENT_IP)
- )
- );
-
- //限制一个应用appId每秒只能调用5次
- //setBurst突发请求额外增加5个
- rules.add(new GatewayFlowRule("open_gateway")
- .setCount(5)
- .setIntervalSec(1)
- .setBurst(5)
- .setParamItem(new GatewayParamFlowItem()
- .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
- .setFieldName("appId")
- )
- );
-
- //限制一个应用appId每秒只能调用5次
- //setBurst突发请求额外增加5个
- rules.add(new GatewayFlowRule("open_gateway")
- .setCount(5)
- .setIntervalSec(1)
- .setBurst(5)
- .setParamItem(new GatewayParamFlowItem()
- .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
- .setFieldName("appId").setPattern("testApp")
- )
- );
-
- GatewayRuleManager.loadRules(rules);
- }
- }
2,自定义响应消息类
- /**
- * @author lr
- * @date 2019-09-12 15:15
- */
- public class OpenBlockRequestHandler implements BlockRequestHandler {
-
- @Override
- public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable ex) {
- // JSON result by default.
- return ServerResponse.status(HttpStatus.OK)
- .contentType(MediaType.APPLICATION_JSON_UTF8)
- .body(fromObject(buildErrorResult(ex)));
- }
-
-
- private ResponseBean buildErrorResult(Throwable ex) {
- return ResponseBeanUtils.getResponseBean(ErrorCode.REQUEST_QPS_LIMIT_ERROR);
- }
- }
四,postman调用结果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。