开发者

Sentinel Gateway自定义限流返回结果方式

目录
  • Sentinel Gateway自定义限流返回结果
    • 1、配置文件配置
    • 2、自定义代码配置
  • 总结

    Sewww.devze.comntinel Gateway自定义限流返回结果

    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>

    通过SentinelSCGAutoConfjsiguration配置类,我们可以看到主要有两种方法可以实现自定义:配置文件配置和自定义代码配置。

    1、配置文件配置

    在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的类型处理模式有两种:responseredirect。在SentinelSCGAutoConfiguration中对应的代码在 initFallback() 方法。

    • response

    如果设置mode为response则返回contentType 类型的responseBody,响应码为responseStatus 。

    • redirect

    如果设置mode为redirect,则限流后自动跳转某个页面,页编程面地址为redirect。

    2、自定义代码配置

    通过Sentinel wiki 我们可以看到:

    Sentinel Gateway自定义限流返回结果方式

    所以我们可以通

    GatewayCallbackManagersetBlockHandler() 方法来实现注册我们自定义的异常处理类,需要实现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.M编程客栈ediaType;
    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
        @AllArgsConandroidstructor
        @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访问限流跳转页面的效果。

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜