温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Spring Cloud Zuul如何实现自定义过滤器

发布时间:2021-03-17 09:15:41 来源:亿速云 阅读:404 作者:小新 栏目:开发技术

小编给大家分享一下Spring Cloud Zuul如何实现自定义过滤器,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

构建Zuul自定义过滤器,限制ip频繁请求

自定义zuul过滤器其实很简单

1. 首先pom文件得先引入zuul依赖

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

2. 创建一个类,继承自ZuulFilter

import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.exception.ZuulException; import org.springframework.stereotype.Component; /**  * 构建zuul自定义过滤器  */ @Component public class MyFilter extends ZuulFilter {   /**    * 定义过滤器的类型    * pre:在请求被路由之前执行    * route:在路由请求的时候执行    * post:请求路由以后执行    * error:处理请求时发生错误的时候执行    *    * @return 过滤器的类型    */   @Override   public String filterType() {     return "pre";   }   /**    * 过滤器执行的顺序,配置多个有顺序的过滤    * 执行顺序从小到大    *    * @return 执行顺序    */   @Override   public int filterOrder() {     return 1;   }   /**    * 是否开启过滤器    * true:开启    * false:禁用    *    * @return 是否开启过滤器    */   @Override   public boolean shouldFilter() {     return true;   }   /**    * 过滤器的业务实现    *    * @return null 没有意义    * @throws ZuulException 异常信息    */   @Override   public Object run() throws ZuulException {     System.out.println("per zuul filter...");     return null;   } }

自定义类上需要加上 @Component 注解
a. filterType()方法,定义过滤器的类型,返回的就是字符串,有以下4种类型

  • pre:在请求被路由之前执行

  • route:在路由请求的时候执行

  • post:请求路由以后执行

  • error:处理请求时发生错误的时候执行

b. filterOrder()方法,过滤器执行的顺序
c. shouldFilter()方法,是否开启过滤器,true开启,false不开启
d. run()方法,过滤器的业务实现,在这里写实现逻辑的具体代码

3. 限制ip频繁请求,示例代码

import com.imooc.grace.result.GraceJsonResult; import com.imooc.grace.result.ResponseStatusEnum; import com.imooc.utils.IPUtil; import com.imooc.utils.JsonUtils; import com.imooc.utils.RedisOperator; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; /**  * 限制ip频繁请求  */ @Component public class BlackIpFilter extends ZuulFilter {   /**    * ip连续请求的次数    */   private static final int CONTINUE_COUNTS = 10;   /**    * ip判断的时间间隔,单位秒    */   private static final int TIME_INTERVAL = 10;   /**    * 限制的时间,单位秒    */   private static final int LIMIT_TIMES = 15;   @Autowired   private RedisOperator redisOperator;   @Override   public String filterType() {     return "pre";   }   @Override   public int filterOrder() {     // 这里设置为2,上面那个过滤器设置为1,则执行顺序为 1->2,大家可以测试一下     return 2;   }   @Override   public boolean shouldFilter() {     return true;   }   @Override   public Object run() throws ZuulException {     // 获取上下文对象     RequestContext currentContext = RequestContext.getCurrentContext();     HttpServletRequest request = currentContext.getRequest();     // 获取ip     String requestIp = IPUtil.getRequestIp(request);     // 判断该ip在10秒内请求次数是否超过10次,超过则限制该ip15秒内不能访问,15秒后再放行     final String ipRedisKey = "zuul-ip:" + requestIp;     final String ipRedisLimitKey = "zuul-ip-limit:" + requestIp;     // 获取当前ip这个key的剩余时间     long limitLeftTime = redisOperator.ttl(ipRedisLimitKey);     // 判断该ip是否还有剩余时间     if (limitLeftTime > 0) {       stopRequest(currentContext);       return null;     }     // 在redis中累加ip的请求次数     long requestCounts = redisOperator.increment(ipRedisKey, 1);     if (requestCounts == 1) {       redisOperator.expire(ipRedisKey, TIME_INTERVAL);     }     if (requestCounts > CONTINUE_COUNTS) {       // 限制ip访问       redisOperator.set(ipRedisLimitKey, ipRedisLimitKey, LIMIT_TIMES);       stopRequest(currentContext);     }     return null;   }   private void stopRequest(RequestContext context) {     // 停止zuul继续向下路由,禁止请求通信     context.setSendZuulResponse(false);     // 返回响应码200     context.setResponseStatusCode(200);     // TODO 要返回提示的json内容(可以自定义任何响应内容)     // 例如 {"status":544,"msg":"请求过于频繁,请稍后再试","success":false,"data":null}     String result = "json内容";     // 设置返回内容     context.setResponseBody(result);     // 设置编码     context.getResponse().setCharacterEncoding("utf-8");     // 设置返回内容格式为json     context.getResponse().setContentType(MediaType.APPLICATION_JSON_VALUE);   } }

这里使用了redis来记录ip请求次数和控制时间间隔

获取ip工具类 IPUtil

import javax.servlet.http.HttpServletRequest; /**  * 获取ip工具类  */ public class IPUtil {   /**    * 获取请求IP:    * 用户的真实IP不能使用request.getRemoteAddr()    * 这是因为可能会使用一些代理软件,这样ip获取就不准确了    * 此外我们如果使用了多级(LVS/Nginx)反向代理的话,ip需要从X-Forwarded-For中获得第一个非unknown的IP才是用户的有效ip。    */   public static String getRequestIp(HttpServletRequest request) {     String ip = request.getHeader("x-forwarded-for");     if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {       ip = request.getHeader("Proxy-Client-IP");     }     if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {       ip = request.getHeader("WL-Proxy-Client-IP");     }     if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {       ip = request.getHeader("HTTP_CLIENT_IP");     }     if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {       ip = request.getHeader("HTTP_X_FORWARDED_FOR");     }     if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {       ip = request.getRemoteAddr();     }     return ip;   } }

看完了这篇文章,相信你对“Spring Cloud Zuul如何实现自定义过滤器”有了一定的了解,如果想了解更多相关知识,欢迎关注亿速云行业资讯频道,感谢各位的阅读!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI