当前位置:   article > 正文

Sentinel Gateway自定义限流返回结果_gatewaycallbackmanager.setblockhandler();

gatewaycallbackmanager.setblockhandler();

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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

1.配置文件配置

在application.yml加入以下配置:

spring:
  cloud:
    sentinel:
      scg:
        fallback:
          mode: response
          responseBody: "{\"code\":\"429\",\"msg\":\"请求太多了\"}"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

对应的配置类为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();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

可以通过配置看到根据mode的类型处理模式有两种:responseredirect。在SentinelSCGAutoConfiguration中对应的代码在 initFallback() 方法。

  • response
    如果设置mode为response则返回contentType 类型的responseBody,响应码为responseStatus 。
  • redirect
    如果设置mode为redirect,则限流后自动跳转某个页面,页面地址为redirect。

2. 自定义代码配置

通过Sentinel wiki 我们可以看到:
在这里插入图片描述所以我们可以通过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.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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

然后再调用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());
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

然后就实现了接口访问限流返回固定值,html访问限流跳转页面的效果。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/301951
推荐阅读
相关标签
  

闽ICP备14008679号