Spring Cloud Alibaba之服务限流降级Sentinel

生活中,最使人疲惫的往往不是道路的遥远,而是心中的郁闷;最使人痛苦的往往不是生活的不幸,而是希望的破灭;最使人颓废的往往不是前途的坎坷,而是自信的丧失;最使人绝望的往往不是挫折的打击,而是心灵的死亡。所以我们要有自己的梦想,让梦想的星光指引着我们走出落漠,走出惆怅,带着我们走进自己的理想。

导读:本篇文章讲解 Spring Cloud Alibaba之服务限流降级Sentinel,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

Sentinel概述

Sentinel: 分布式系统的流量防卫兵

Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel 分为两个部分:

核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。

控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

Sentinel 的主要特性:
在这里插入图片描述
Sentinel 的开源生态:
在这里插入图片描述

GitHub地址: https://github.com/alibaba/Sentinel

官网: https://sentinelguard.io/zh-cn/

项目集成Sentinel

相关依赖

	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/>
    </parent>

    <dependencyManagement>
        <dependencies>
            <!--整合spring cloud-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR9</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--整合spring cloud alibaba-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

在Sentinel控制台搭建成功后配置Sentinel

spring:
  cloud:
    sentinel:
      transport:
        # 指定sentinel 控制台的地址
        dashboard: IP:8858

查看Sentinel端点

暴露端点

management:
  endpoints:
    web:
      exposure:
        include: '*'

访问: http://localhost:8082/actuator/sentinel

{
  "blockPage": null,
  "appName": "pay-center",
  "consoleServer": [
    
  ],
  "coldFactor": "3",
  "rules": {
    "systemRules": [
      
    ],
    "authorityRule": [
      
    ],
    "paramFlowRule": [
      
    ],
    "flowRules": [
      
    ],
    "degradeRules": [
      
    ]
  },
  "metricsFileCharset": "UTF-8",
  "filter": {
    "order": -2147483648,
    "urlPatterns": [
      "/**"
    ],
    "enabled": true
  },
  "totalMetricsFileCount": 6,
  "datasource": {
    
  },
  "clientIp": "192.168.42.16",
  "clientPort": "8719",
  "logUsePid": false,
  "metricsFileSize": 52428800,
  "logDir": "C:\\Users\\Administrator\\logs\\csp\\",
  "heartbeatIntervalMs": 10000
}

Sentinel控制台

首先确定spring-cloud-alibaba对应Sentinel版本,然后搭建对应版本的Sentinel控制台

		<!--点击artifactId进入spring-cloud-alibaba依赖管理中查看nacos的版本-->
		<dependency>
             <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>


<sentinel.version>1.8.1</sentinel.version>

Docker部署Sentine

https://blog.csdn.net/qq_38628046/article/details/106875278

添加Sentinel的配置并重启项目

spring:
  cloud:
    sentinel:
      transport:
        # 指定sentinel 控制台的地址
        dashboard: IP:8858

由于Sentinel是懒加载,需要访问如(http://192.168.179.1:8082/test/1)任一接口一次才会出现相应服务
在这里插入图片描述
多次访问接口,发现无任何监控信息
在这里插入图片描述
查看Docker容器日志,发现似乎是Ip的原因造成的,且IP陌生。

 ERROR 1 --- [pool-2-thread-1] c.a.c.s.dashboard.metric.MetricFetcher   : Failed to fetch metric from <http://192.168.42.16:8719/metric?startTime=1638617140000&endTime=1638617146000&refetch=false> (ConnectionException: Connection timed out)


 ERROR 1 --- [pool-2-thread-1] c.a.c.s.dashboard.metric.MetricFetcher   : Failed to fetch metric from <http://192.168.42.16:8719/metric?startTime=1638617147000&endTime=1638617153000&refetch=false> (ConnectionException: Connection timed out)


 ERROR 1 --- [pool-2-thread-1] c.a.c.s.dashboard.metric.MetricFetcher   : Failed to fetch metric from <http://192.168.42.16:8719/metric?startTime=1638617154000&endTime=1638617160000&refetch=false> (ConnectionException: Connection timed out)


 ERROR 1 --- [pool-2-thread-1] c.a.c.s.dashboard.metric.MetricFetcher   : Failed to fetch metric from <http://192.168.42.16:8719/metric?startTime=1638617161000&endTime=1638617167000&refetch=false> (ConnectionException: Connection timed out)

关闭服务,然后在sentinel控制台的机器列表移除错误的机器IP
在这里插入图片描述
修改Sentinel配置

spring:
  cloud:
    sentinel:
      transport:
        # 指定sentinel 控制台的地址
        dashboard: IP:8858
        #指定和控制台通信的ip,如不配置,会自动选择一个ip注册,可能造成错误
        clientIp: localhost

重启服务
在这里插入图片描述
多次访问http://192.168.179.1:8082/test/1接口服务
在这里插入图片描述
请求test/{id}接口,实时监控中没有发现该接口,折腾许久未找到原因,无解,于是直接下载Jar,本地运行。

下载地址:https://github.com/alibaba/Sentinel/releases

java -jar sentinel-dashboard-1.8.1.jar

修改Sentinel配置(改Sentinel服务地址为本机),访问http://localhost:8082/test/1服务地址,最后访问http://localhost:8080/
在这里插入图片描述

Sentinel的各种规则

流控规则

流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

一条限流规则主要由下面几个因素组成,可以组合这些元素来实现不同的限流效果:

resource:资源名,即限流规则的作用对象

count: 限流阈值

grade: 限流阈值类型(QPS 或并发线程数)

limitApp: 流控针对的调用来源,若为 default 则不区分调用来源

strategy: 调用关系限流策略

controlBehavior: 流量控制效果(直接拒绝、Warm Up、匀速排队)

在这里插入图片描述在这里插入图片描述
流量控制主要有两种统计类型

统计并发线程数

统计QPS

基于调用关系的流量控制

直接    

关联    

链路  

当QPS超过某个阈值的时候,则采取措施进行流量控制

直接拒绝

Warm Up

匀速排队

直接拒绝

直接拒绝(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。

源码类: com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController

Warm Up

Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过”冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

根据codeFactor(默认3)的值,从阈值/codeFactor,经过预热时长才到达设置的QPS阈值

官方原理分析文档
https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8

源码:com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController

匀速排队

匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。

匀速排队,让请求以均匀的速度通过,或值类型必须设成QPS,否则无效

官方文档
https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6-%E5%8C%80%E9%80%9F%E6%8E%92%E9%98%9F%E6%A8%A1%E5%BC%8F

源码: com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController

流控测试

直接流控模式
在这里插入图片描述
当Qps超过1则报异常,进行限流。
在这里插入图片描述
关联流控模式

当关联的资源达到阈值,就限流自己

在这里插入图片描述
先循环执行调用/test2接口,再访问/test/{id}接口,/test/{id}接口将一直处于限流状态

链路流控模式

只记录指定链路上的流量

@Component
public class TestComponent {
    @SentinelResource("common")
    public String common() {
        return "common";
    }
}
  @GetMapping("test-a")
    public String testA() {
        this.testService.common();
        return "test-a";
    }
    
    @GetMapping("test-b")
    public String testB() {
        this.testService.common();
        return "test-b";
    }

在这里插入图片描述
当访问test-a接口达到Qps时限流,而无论如何访问test-b都不会限流

降级规则

一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。

因此需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。

在这里插入图片描述
Sentinel熔断策略:

慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% – 100%。

异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

熔断降级规则重要属性:

Field 说明 默认值
resource 资源名,即规则的作用对象
grade 熔断策略,支持慢调用比例/异常比例/异常数策略 慢调用比例
count 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
timeWindow 熔断时长,单位为 s
minRequestAmount 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) 5
statIntervalMs 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) 1000 ms
slowRatioThreshold 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)

参考源码: com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule

热点参数限流

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
在这里插入图片描述
添加/testParam接口

   @GetMapping("/testParam")
    @SentinelResource("param")
    public String testParam(Integer a,String b){
        return a + "-------------" +b;
    }

在这里插入图片描述

请求http://localhost:8082/testParam?a=1&b=Sentinel,由于对第一个参数限制,当Qps达到1则限流抛出异常

在这里插入图片描述
请求http://localhost:8082/testParam?a=&b=Sentinel,无论如何请求都不会限流
在这里插入图片描述
在这里插入图片描述

当第一个参数值不是2时,Qps达到1则限流

当第一个参数值是2时,Qps达到100则限流

参考源码: com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowChecker

系统规则

系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

在这里插入图片描述

Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的maxQps * minRt估算得出。设定参考值一般是 CPU cores * 2.5

CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。

平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。

并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。

入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

参考源码: com.alibaba.csp.sentinel.slots.system.SystemRuleManager

授权规则

根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
在这里插入图片描述

Sentinel的规则持久化

拉模式:

客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;

推模式:

规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。

具体实现参考:https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95

Sentinel的配置

应用端连接控制台的配置

spring:
  cloud:
    sentinel:
      transport:
        # 指定sentinel 控制台的地址
        dashboard: IP:8858
        #指定和控制台通信的ip,如不配置,会自动选择一个ip注册,可能造成错误
        clientIp: localhost
        # 指定和控制台通信的端口,默认值8719
        # 如不设置,会自动从8719开始扫描,依次+1,直到找到未被占用的端口
        port: 8719
        # 心跳发送周期,默认值null,但在SimpleHttpHeartbeatSender会用默认值10秒
        heartbeat-interval-ms: 10000

控制台配置

配置项 默认值 描述
server.port 8080 指定端口
csp.sentinel.dashboard.server localhost:8080 指定地址
project.name 指定程序的名称
sentinel.dashboard.auth.username sentinel Dashboard登录账号
sentinel.dashboard.auth.password sentinel Dashboard登录密码
server.servlet.session.timeout 30分钟 登录Session过期时间
配置为7200表示7200秒
配置为60m表示60分钟

Sentinel的使用

API方式

三个核心API:

SphU :定义资源,让资源受到监控,以及保护资源

Tacer:对想要的异常进行统计

ContextUtil: 实现调用来源,标记调用

注意异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。

    @GetMapping("/test-api")
    public String testSentinelAPI(@RequestParam(required = false) String name) {
        // 定义资源名称
        String resourceName = "test-api";
        //  实现调用来源,标记调
        ContextUtil.enter(resourceName, "test-service");

        Entry entry = null;
        try {
            entry = SphU.entry(resourceName);
            // 被保护的业务逻辑
            if (StringUtils.isBlank(name)) {
                throw new IllegalArgumentException("参数不合法");
            }
            return name;
        }
        // 如果被保护的资源被限流或者降级,就会抛BlockException
        catch (BlockException blockException) {
            return "限流或者降级";
        } catch (IllegalArgumentException illegalArgumentException) {
        	// 自行调用 Tracer.trace(ex) 来记录业务异常
            Tracer.trace(illegalArgumentException);
            return "参数不合法";
        } finally {
            if (entry != null) {
                // 退出entry
                entry.exit();
            }
            ContextUtil.exit();
        }
    }

注解方式

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback配置项

使用详情参考: https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81

 @GetMapping("/test-sentinel-resource")
    @SentinelResource(
            value = "test-sentinel-api",
            blockHandler = "block",
            //blockHandlerClass = BlockHandlerTestClass.class,
            //fallbackClass = FallbackTestClass.class,
            fallback = "fallback"
    )
    public String testSentinelResource(@RequestParam(required = false) String name) {
        if (StringUtils.isBlank(name)) {
            throw new IllegalArgumentException("参数不合法");
        }
        return name;
    }

    public String block(String name, BlockException blockException) {
        return "限流或者降级---------block";
    }

    public String fallback(String name, Throwable throwable) {
        return "限流或者降级---------fallback";
    }

将block()与fallback()进行抽离,使用blockHandlerClass与fallbackClass分别指定

 @GetMapping("/test-sentinel-resource")
    @SentinelResource(
            value = "test-sentinel-api",
            blockHandler = "block",
            blockHandlerClass = BlockHandlerTestClass.class,
            fallbackClass = FallbackTestClass.class,
            fallback = "fallback"
    )
    public String testSentinelResource(@RequestParam(required = false) String name) {
        if (StringUtils.isBlank(name)) {
            throw new IllegalArgumentException("参数不合法");
        }
        return name;
    }

blockHandlerClass = BlockHandlerTestClass.clas:对应的 block 函数需要位于 BlockHandlerTestClass 类中,并且必须为 public static 函数.

fallbackClass = FallbackTestClass.class:对应的 fallback 函数需要位于 FallbackTestClass 类中,并且必须为 public static 函数.

public class BlockHandlerTestClass{
    /**
     * 处理限流或者降级
     */
    public static String block(String name, BlockException blockException) {
        return "BlockHandlerTestClass----限流或者降级-------block";
    }
}

与RestTemplate和Feign集成

RestTemplate集成Sentinel

@SentinelRestTemplate注解同样提供fallback与blockHandler的处理

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SentinelRestTemplate {
    String blockHandler() default "";

    Class<?> blockHandlerClass() default void.class;

    String fallback() default "";

    Class<?> fallbackClass() default void.class;

    String urlCleaner() default "";

    Class<?> urlCleanerClass() default void.class;
}

定义限流降级异常处理类

public class BlockHandler {
    public static SentinelClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution clientHttpRequestExecution, BlockException blockException) {
        return new SentinelClientHttpResponse("限流或者降级---------BlockHandler Class");
    }
}
public class FallBackHandler {
 
    public static SentinelClientHttpResponse fallBackHandle(HttpRequest request, byte[] body, ClientHttpRequestExecution clientHttpRequestExecution, BlockException blockException){
        return new SentinelClientHttpResponse("限流或者降级---------FallBackHandler Class");
    }
}

RestTemplate添加@SentinelRestTemplate注解

    @Bean
    //Ribbon负载均衡
    @LoadBalanced
    //让RestTemplate支持Sentinel限流
    @SentinelRestTemplate(blockHandler = "handleException",blockHandlerClass = BlockHandler.class,
            fallback = "fallBackHandle", fallbackClass = FallBackHandler.class)
    public RestTemplate restTemplate() {
        RestTemplate template = new RestTemplate();
        return template;
    }
}

@SentinelRestTemplate注解配置可关闭

resttemplate:
  sentinel:
  	# 开发环境可以临时关闭: 降级,限流
    # 默认true,设置成false,表示关闭@SentinelRestTemplate注解
    enabled: false

Feign集成Sentinel

开启Feign对Sentinel的支持

feign:
  sentinel:
    # 为feign整合sentinel
    enabled: true

创建限流降级容错类

直接实现被容错的接口,并为每个方法实现容错方案

实现FallbackFactory接口
@Component
public class UserCenterFeignClientFallback implements UserCenterFeignClient {
    @Override
    public UserDTO selectUserById(Integer id) {
        UserDTO userDTO = new UserDTO();
        userDTO.name("流控或降级-------implements UserCenterFeignClient");
        return userDTO;
    }
}
@Component
public class UserCenterFeignClientFallbackFactory implements FallbackFactory<UserCenterFeignClient> {
    @Override
    public UserCenterFeignClient create(Throwable cause) {
        return new UserCenterFeignClient() {
            @Override
            public UserDTO selectUserById(Integer id) {
                UserDTO userDTO = new UserDTO();
                userDTO.name("流控或降级-------implements FallbackFactory");
                return userDTO;
            }
        };
    }
}

为被限流降级容错的interface指定容错类

@FeignClient(name = "user-center",
//    fallback = UserCenterFeignClientFallback.class,
    fallbackFactory = UserCenterFeignClientFallbackFactory.class
)
public interface UserCenterFeignClient {
    @GetMapping("/users/{id}")
    UserDTO selectUserById(@PathVariable Integer id);
}

Sentinel的异常处理

统一处理返回异常: 实现BlockExceptionHandler接口重写handle()方法。

@Component
public class MyUrlBlockHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, BlockException e) throws Exception {
        String msg = null;
        if (e instanceof FlowException) {
            msg = "限流---------FlowException";
        } else if (e instanceof DegradeException) {
            msg = ("降级---------DegradeException";
        } else if (e instanceof ParamFlowException) {
            msg = "热点参数限流---------ParamFlowException";
        } else if (e instanceof SystemBlockException) {
            msg = "系统规则---------SystemBlockException";
        } else if (e instanceof AuthorityException) {
            msg = "授权规则不通过---------AuthorityException";
        }

        response.setStatus(500);
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        response.setContentType("application/json;charset=utf-8");
        new ObjectMapper().writeValue(response.getWriter(), msg);
    }

Sentinel实现来源区分

代码实现

@Component
public class MyRequestOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        // 从请求头/请求参数中获取名为origin的参数
//        String origin = request.getHeader("request");
        String origin = request.getParameter("origin");

        // 获取不到origin参数则抛异常
        if (StringUtils.isBlank(origin)) {
            throw new IllegalArgumentException("请求不合法");
        }
        return origin;
    }
}

针对来源限流测试

在这里插入图片描述
请求:http://localhost:8082/test?origin=web

限流---------FlowException

请求:http://localhost:8082/test?origin=app : 随便访问

针对来源授权测试

在这里插入图片描述
请求:http://localhost:8082/test?origin=app

授权规则不通过---------AuthorityException

请求:http://localhost:8082/test?origin=web : 通过

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/137015.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!