springcloud-gateway全局过滤、限流与熔断

目录

路由断言

Spring Cloud Gateway可以进行多种方式的路由断言,以路径方式为例,在application.properties配置文件中增加以下配置:

spring.cloud.gateway.routes[0].id=route_test1
spring.cloud.gateway.routes[0].uri=lb://springCloud-test
spring.cloud.gateway.routes[0].predicates[0]=Path=/test/**

其中:

  • id:该过滤器ID
  • uri:path匹配的请求自动转发到此地址
  • path:路径匹配内容

实现效果为

在这里插入图片描述

GlobalFilter全局过滤

在SpringCloud生态系中,可以通过GlobalFilter在Spring Cloud Gateway对所有http请求进行全局过滤,实现包括请求鉴权等功能在内的业务需求。
Spring Cloud Gateway使用的是webflux模式,如何从请求参数中提取到相关数据,特别是针对POST请求如何提取数据,根据springboot和springcloud版本的不同有不同的处理方式,本文采用的版本为:

<spring-boot.version>2.1.2.RELEASE</spring-boot.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>

此版本下经过参考过多个教程,最终确定采用的是Springcloud gateway获取post请求内容这篇文章的处理方法,以请求鉴权为例,代码为:

@Component
public class AuthTestFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest serverHttpRequest = exchange.getRequest();
        String method = serverHttpRequest.getMethodValue();
        System.out.println(method);
        String contentType = serverHttpRequest.getHeaders().getFirst("Content-Type");
        if (StringUtil.isNullOrEmpty(contentType)){
            contentType = "DEFAULT";
        }
        if(method.equals("POST")||contentType.startsWith("multipart/form-data")){
            return DataBufferUtils.join(exchange.getRequest().getBody())
                    .flatMap(dataBuffer -> {
                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bytes);
                        try {
                            String bodyString = new String(bytes, "utf-8");
                            System.out.println(formatStr(bodyString));
                            JSONObject json = JSON.parseObject(bodyString);
                            String token = json.getString("token");
                            if(authCheck(token)){
                                exchange.getAttributes().put("POST_BODY",bodyString);
                            }else {
                                ServerHttpResponse response = exchange.getResponse();
                                JSONObject responseBody = new JSONObject();
                                responseBody.put("msg","鉴权失败");
                                byte[] bits = responseBody.toJSONString().getBytes(StandardCharsets.UTF_8);
                                DataBuffer buffer2 = response.bufferFactory().wrap(bits);
                                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                                response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
                                return response.writeWith(Mono.just(buffer2));
                            }

                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        DataBufferUtils.release(dataBuffer);
                        Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                            DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                            return Mono.just(buffer);
                        });

                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                exchange.getRequest()) {
                            @Override
                            public Flux<DataBuffer> getBody() {
                                return cachedFlux;
                            }
                        };
                        return chain.filter(exchange.mutate().request(mutatedRequest).build());
                    });

        }else if(method.equals("GET")){
            String token = serverHttpRequest.getQueryParams().getFirst("token");
            System.out.println(token);
            if(authCheck(token)){
                return chain.filter(exchange);
            }else {
                ServerHttpResponse response = exchange.getResponse();
                JSONObject responseBody = new JSONObject();
                responseBody.put("msg","鉴权失败");
                byte[] bits = responseBody.toJSONString().getBytes(StandardCharsets.UTF_8);
                DataBuffer buffer2 = response.bufferFactory().wrap(bits);
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
                return response.writeWith(Mono.just(buffer2));
            }
        }
        return null;
    }

    @Override
    public int getOrder() {
        return 0;
    }

    private String formatStr(String str){
        if (str != null && str.length() > 0) {
            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(str);
            return m.replaceAll("");
        }
        return str;
    }

    public boolean authCheck(String token){
        if(token.equals("qwe")){
            return true;
        }else {
            return false;
        }
    }
}

测试结果为:
GET:

在这里插入图片描述

POST:

在这里插入图片描述

限流

Spring Cloud Gateway可以通过Redis实现限流,限流的基本原理与实现方式可以参考SpringCloudGateWay系列四:限流
首先在pom.xml中增加如下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

并且需要安装配置Redis

之后设计限流类型,这里以请求地址为限流依据,指定具体的限流key:

public class ApiKeyResolver implements KeyResolver {

    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        return Mono.just(exchange.getRequest().getPath().value());
    }
}

@Component
public class RequestLimitCustomTest {

    @Bean(name = "apiKeyResolver")
    public ApiKeyResolver apiKeyResolver(){
        return new ApiKeyResolver();
    }

}

之后需要进行redis配置

spring.redis.host=10.18.226.209
spring.redis.port=6379
spring.redis.database=0

特定路径限流

在application.properties配置文件中增加以下配置

spring.cloud.gateway.routes[0].id=route_test1
spring.cloud.gateway.routes[0].uri=lb://springCloud-test
spring.cloud.gateway.routes[0].predicates[0]=Path=/test/**
spring.cloud.gateway.routes[0].filters[0].name=RequestRateLimiter2
#自定义的bean
spring.cloud.gateway.routes[0].filters[0].args[key-resolver]=#{@apiKeyResolver}
#每秒允许访问次数
spring.cloud.gateway.routes[0].filters[0].args[redis-rate-limiter.replenishRate]=3
#令牌桶容量
spring.cloud.gateway.routes[0].filters[0].args[redis-rate-limiter.burstCapacity]=10

凡是符合过滤要求的请求会受到限流

全局限流

在application.properties配置文件中增加以下配置

spring.cloud.gateway.default-filters[0].name=RequestRateLimiter
spring.cloud.gateway.default-filters[0].args[key-resolver]=#{@apiKeyResolver}
#每秒允许访问次数
spring.cloud.gateway.default-filters[0].args[redis-rate-limiter.replenishRate]=3
#令牌桶容量
spring.cloud.gateway.default-filters[0].args[redis-rate-limiter.burstCapacity]=10

默认对所有请求进行过滤,测试效果为:

在这里插入图片描述

可以看到一秒内请求数超过限制,之后的请求即返回失败

熔断

Spring Cloud Gateway可以通过Hystrix实现熔断
首先增加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

之后自定义熔断返回结果

@RestController
public class fallbackController {

    @RequestMapping("/hystrixfallback")
    public Map<String,String> defaultfallback(){
        System.out.println("熔断");
        Map<String,String> map = new HashMap<>();
        map.put("resultCode","1");
        map.put("resultMessage","服务异常");
        map.put("resultObj","null");
        return map;
    }

}

在配置文件中配置hystrix

hystrix.metrics.enabled=true
#超时时间
hystrix.metrics.polling-interval-ms=2000
#转移线程
hystrix.shareSecurityContext=true

此时关闭微服务,测试熔断机制:

在这里插入图片描述

原文地址:https://blog.csdn.net/yorao4565/article/details/113865739

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

相关推荐


Nacos 中的参数有很多,如:命名空间、分组名、服务名、保护阈值、服务路由类型、临时实例等,那这些参数都是什么意思?又该如何设置?接下来我们一起来盘它。 1.命名空间 在 Nacos 中通过命名空间(Namespace)+ 分组(Group)+服务名(Name)可以定位到一个唯一的服务实例。 命名
Nacos 支持两种 HTTP 服务请求,一个是 REST Template,另一个是 Feign Client。之前的文章咱们介绍过 Rest Template 的调用方式,主要是通过 Ribbon(负载均衡) + RestTemplate 实现 HTTP 服务调用的,请求的核心代码是这样的: @
Nacos 是 Spring Cloud Alibaba 中一个重要的组成部分,它提供了两个重要的功能:服务注册与发现和统一的配置中心功能。 服务注册与发现功能解决了微服务集群中,调用者和服务提供者连接管理和请求转发的功能,让程序的开发者无需过多的关注服务提供者的稳定性和健康程度以及调用地址,因为这
Spring Cloud Alibaba 是阿里巴巴提供的一站式微服务开发解决方案,目前已被 Spring Cloud 官方收录。而 Nacos 作为 Spring Cloud Alibaba 的核心组件之一,提供了两个非常重要的功能:服务注册中心(服务注册和发现)功能,和统一配置中心功能。 Nac
在 Nacos 的路由策略中有 3 个比较重要的内容:权重、保护阈值和就近访问。因为这 3 个内容都是彼此独立的,所以今天我们就单独拎出“保护阈值”来详细聊聊。 保护阈值 保护阈值(ProtectThreshold):为了防止因过多实例故障,导致所有流量全部流入剩余健康实例,继而造成流量压力将剩余健
前两天遇到了一个问题,Nacos 中的永久服务删除不了,折腾了一番,最后还是顺利解决了。以下是原因分析和解决方案,建议先收藏,以备不时之需。 临时实例和持久化实例是 Nacos 1.0.0 中新增了一个特性。临时实例和持久化实例最大的区别是健康检查的方式:临时实例使用客户端主动上报的健康检查模式,而
Spring Cloud Alibaba 技术体系中的 Nacos,提供了两个重要的功能:注册中心(服务注册与发现)功能和配置中心功能。 其中注册中心解决了微服务调用中,服务提供者和服务调用者的解耦,让程序开发者可以无需过多的关注服务提供者和调用者的运行细节,只需要通过 Nacos 的注册中心就可以
负载均衡通器常有两种实现手段,一种是服务端负载均衡器,另一种是客户端负载均衡器,而我们今天的主角 Ribbon 就属于后者——客户端负载均衡器。 服务端负载均衡器的问题是,它提供了更强的流量控制权,但无法满足不同的消费者希望使用不同负载均衡策略的需求,而使用不同负载均衡策略的场景确实是存在的,所以客
本篇文章为大家展示了如何解决Spring Cloud 服务冲突问题,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、背景...
本篇内容主要讲解“spring cloud服务的注册与发现怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“spri...
本篇内容介绍了“Dubbo怎么实现Spring Cloud服务治理 ”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处...
本篇内容主要讲解“SpringCloud相关面试题有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SpringCloud相...
如何分析Spring Cloud Ribbon、Spring Cloud Feign以及断路器,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希
这篇文章主要讲解了“springcloud微服务的组成部分有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“s...
这篇文章主要讲解了“SpringCloud的OpenFeign项目怎么创建”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习...
本篇内容主要讲解“spring cloud oauth3整合JWT后获取用户信息不全怎么办”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带...
怎样解析微服务架构SpringCloud,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。...
这篇文章主要介绍spring cloud中API网关的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、服务网关简介1、外观模式客户端...
本篇内容介绍了“Spring Cloud微服务的相关问题有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处...
本文小编为大家详细介绍“spring cloud config整合gitlab如何搭建分布式的配置中心”,内容详细,步骤清晰,细节处理妥当,希望这篇“spring cloud config整合gi...