赞
踩
sentinel在1.6.0后就引入了Sentinel API Gateway Adapter Common,适配了Gateway。
以前sentinel自定义限流结果是通过实现BlockExceptionHandler接口进行自定义限流返回结果,但是如果是使用了spring-cloud-alibaba-sentinel-gateway的依赖进行限流的话,使用之前的接口是不起作用的。
首先是我本地项目的环境,适配的是springboot 2.3.12.RELEASE版本,cloud版本为Hoxton.SR12。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
通过SentinelSCGAutoConfiguration配置类,我们可以看到主要有两种方法可以实现自定义:配置文件配置和自定义代码配置。
在application.yml加入以下配置:
spring:
cloud:
sentinel:
scg:
fallback:
mode: response
responseBody: "{\"code\":\"429\",\"msg\":\"请求太多了\"}"
对应的配置类为FallbackProperties,以下是详细的配置:
/** * The fallback mode for sentinel spring-cloud-gateway. choose `redirect` or * `response`. */ private String mode; /** * Redirect Url for `redirect` mode. */ private String redirect; /** * Response Body for `response` mode. */ private String responseBody; /** * Response Status for `response` mode. */ private Integer responseStatus = HttpStatus.TOO_MANY_REQUESTS.value(); /** * Content-Type for `response` mode. */ private String contentType = MediaType.APPLICATION_JSON.toString();
可以通过配置看到根据mode的类型处理模式有两种:response和redirect。在SentinelSCGAutoConfiguration中对应的代码在 initFallback() 方法。
通过Sentinel wiki 我们可以看到:
所以我们可以通过GatewayCallbackManager的 setBlockHandler() 方法来实现注册我们自定义的异常处理类,需要实现BlockRequestHandler接口,默认的异常处理类是:DefaultBlockRequestHandler。
首先自定义一个异常处理类:
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.net.URI; import java.util.List; import static org.springframework.web.reactive.function.BodyInserters.fromValue; /** * @author TYH * @Description: Sentinel异常处理类 * @date 2022/3/8 14:34 */ public class SentinelBlockRequestHandler implements BlockRequestHandler { @Override public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) { // 判断是否是html访问,如果是则转发url if (acceptsHtml(exchange)) { return htmlErrorResponse(); } // 如果是接口访问,则返回提示 return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS) .contentType(MediaType.APPLICATION_JSON_UTF8) .body(fromValue(new ResponseData(HttpStatus.TOO_MANY_REQUESTS.value(),"请求太多了"))); } private Mono<ServerResponse> htmlErrorResponse() { String url="http://www.baidu.com"; URI uri =URI.create(url); return ServerResponse.temporaryRedirect(uri).build(); } private boolean acceptsHtml(ServerWebExchange exchange) { try { List<MediaType> acceptedMediaTypes = exchange.getRequest().getHeaders().getAccept(); acceptedMediaTypes.remove(MediaType.ALL); MediaType.sortBySpecificityAndQuality(acceptedMediaTypes); return acceptedMediaTypes.stream() .anyMatch(MediaType.TEXT_HTML::isCompatibleWith); } catch (InvalidMediaTypeException ex) { return false; } } /** * 定义返回的实体类,字段根据需要添加 */ @Data @AllArgsConstructor @NoArgsConstructor static class ResponseData { private int code; private String msg; } }
然后再调用GatewayCallbackManager的方法进行注册:
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Configuration; /** * @author TYH * @Description: * @date 2022/3/8 15:02 */ @Slf4j @Configuration public class InitConfig implements CommandLineRunner { @Override public void run(String... args) throws Exception { log.info("初始化限流handler"); GatewayCallbackManager.setBlockHandler(new SentinelBlockRequestHandler()); } }
然后就实现了接口访问限流返回固定值,html访问限流跳转页面的效果。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。