Spring Cloud Zuul过滤器 Spring Cloud Zuul自定义过滤器的实现
_灯火阑珊处 人气:0想了解Spring Cloud Zuul自定义过滤器的实现的相关内容吗,_灯火阑珊处在本文为您仔细讲解Spring Cloud Zuul过滤器的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点: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; } }
加载全部内容