SpringCloud H版 GateWay 过滤器讲解 及 使用Guava 统一限流处理。

Posted 小毕超

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud H版 GateWay 过滤器讲解 及 使用Guava 统一限流处理。相关的知识,希望对你有一定的参考价值。

一、GateWay

在上篇文章我们讲解了GateWay 的基本使用和路由的转发,在GateWay 中还有一个重要的知识点就是过滤器,基于过滤器我们可以限制请求的规范,比如过滤请求中token过期的请求,不做转发,或者在网关处对整个服务进行限流控制,保护内容服务的安全。

上篇文章地址:https://blog.csdn.net/qq_43692950/article/details/122023067

在上篇文章中就有提及过滤器,比如配制代理时,不要携带前缀,就使用了- StripPrefix=1,GateWay 提供了很多自带的过滤器,大家也可以参考下每个官方的介绍,文本主要讲解如果自定义过滤器。

官方文档: https://docs.spring.io/spring-cloud-gateway/docs/3.0.5-SNAPSHOT/reference/html/

二、自定义过滤请求参数

教研过滤 参数和header

@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
    
        ServerHttpResponse response = exchange.getResponse();
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders header = response.getHeaders();
        header.add("Content-Type", "application/json; charset=UTF-8");

        String uid = request.getQueryParams().getFirst("uid");
        if(StringUtils.isEmpty(uid))
            JSONObject jsonObject = setResultErrorMsg("参数中必须传递uid");
            DataBuffer buffer = response.bufferFactory().wrap(jsonObject.toJSONString().getBytes());
            return response.writeWith(Mono.just(buffer));
        
        List<String> list = exchange.getRequest().getHeaders().get("token");
        if(list == null || list.isEmpty())
        
            JSONObject jsonObject = setResultErrorMsg("header中必须传递token");
            DataBuffer buffer = response.bufferFactory().wrap(jsonObject.toJSONString().getBytes());
            return response.writeWith(Mono.just(buffer));
        

        return chain.filter(exchange);
    

    @Override
    public int getOrder()
    
        return 1;
    

    private JSONObject setResultErrorMsg(String msg) 
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "406");
        jsonObject.put("message", msg);
        return jsonObject;
    

浏览器请求其中一个转发接口,不传递任何参数:

添加上uid

下面在header中加入token

三、结合 Guava做接口的限流

@Component
@Slf4j
public class LimitFilter implements GlobalFilter, Ordered

    //创建一个限流器,参数代表每秒生成的令牌数(用户限流频率设置 每秒中限制0.1个请求)
    private RateLimiter rateLimiter = RateLimiter.create(0.1);
    @Value("$seckill.intercept.url")
    private List<String> gatewaySeckillInterceptUrl;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) 
        ServerHttpResponse response = exchange.getResponse();
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders header = response.getHeaders();
        header.add("Content-Type", "application/json; charset=UTF-8");
        RequestPath path = request.getPath();
        
        //设置等待超时时间的方式获取令牌,如果超timeout为0,则代表非阻塞,获取不到立即返回
        boolean tryAcquire = rateLimiter.tryAcquire(1, TimeUnit.SECONDS);
        if (!tryAcquire) 
            JSONObject jsonObject = setResultErrorMsg("当前访问用户过多,请稍后重试");
            DataBuffer buffer = response.bufferFactory().wrap(jsonObject.toJSONString().getBytes());
            return response.writeWith(Mono.just(buffer));
        
        // 放行
        return chain.filter(exchange);
    

    private JSONObject setResultErrorMsg(String msg) 
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "406");
        jsonObject.put("message", msg);
        return jsonObject;
    


    @Override
    public int getOrder()
    
        return 0;
    

上面为了容易实现效果,配制了每秒生成0.1个请求,也就是10秒允许1个请求:


只要10秒内请求两次就可以出现上面这种情况。这种情况会将所有请求一律走限流处理。下面也可以修改为根据参数限流,限制每个url的并发请求,过滤器修改:

@Component
public class SeckillFilter implements GlobalFilter 
    //创建一个限流器,参数代表每秒生成的令牌数(用户限流频率设置 每秒中限制1个请求)
    private RateLimiter rateLimiter = RateLimiter.create(1);
    @Value("$gateway.seckill.intercept.url")
    private List<String> gatewaySeckillInterceptUrl;

    LoadingCache<String, RateLimiter> ipRequestCaches = CacheBuilder.newBuilder()
            .maximumSize(1000)// 设置缓存个数
            .expireAfterWrite(1, TimeUnit.MINUTES)
            .build(new CacheLoader<String, RateLimiter>() 
                @Override
                public RateLimiter load(String s) throws Exception 
                    return RateLimiter.create(0.1);//  (限流每秒0.1个令牌响应,即10s一个令牌)
                
            );

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) 
        ServerHttpResponse response = exchange.getResponse();
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders header = response.getHeaders();
        header.add("Content-Type", "application/json; charset=UTF-8");
        RequestPath path = request.getPath();

        RateLimiter rateLimiter = null;
        try 
            rateLimiter = ipRequestCaches.get(request.getURI().toString());
         catch (ExecutionException e) 
            e.printStackTrace();
        
        boolean tryAcquire = rateLimiter.tryAcquire();
        if (!tryAcquire) 
            JSONObject jsonObject = setResultErrorMsg("当前访问用户过多,请稍后重试");
            DataBuffer buffer = response.bufferFactory().wrap(jsonObject.toJSONString().getBytes());
            return response.writeWith(Mono.just(buffer));
        
        // 放行
        return chain.filter(exchange);
    


    private JSONObject setResultErrorMsg(String msg) 
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "406");
        jsonObject.put("message", msg);
        return jsonObject;
    

    public static String getParam(String url, String name) 
        String params = url.substring(url.indexOf("?") + 1, url.length());
        Map<String, String> split = Splitter.on("&").withKeyValueSeparator("=").split(params);
        return split.get(name);
    


其实上面的也可以修改为根据token进行限流,这样就限制一个用户的请求的频率了。


喜欢的小伙伴可以关注我的个人微信公众号,获取更多学习资料!

以上是关于SpringCloud H版 GateWay 过滤器讲解 及 使用Guava 统一限流处理。的主要内容,如果未能解决你的问题,请参考以下文章

SpringCloud H版 GateWay 网关路由讲解

SpringCloud(Greenwich版)新一代API网关Gateway

#yyds干货盘点# springcloud整合gateway实现网关全局过滤器功能

SpringCloud-Gateway 网关路由断言过滤

SpringCloud 统一网关Gateway -- 全局过滤器 GlobalFilter@Order注解过滤器链执行顺序Gateway跨域问题处理

SpringCloud 统一网关Gateway -- 全局过滤器 GlobalFilter@Order注解过滤器链执行顺序Gateway跨域问题处理