springcloud中zuul的应用
来源:互联网 发布:ping端口号指令 编辑:程序博客网 时间:2024/05/29 10:12
zuul常用作网关服务,本例使用zuul作为网关限流服务
一.pom.xml依赖
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix</artifactId> <version>1.2.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency>
二.注册zuul过滤器
package zuul;import java.io.IOException;import java.util.Enumeration;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.http.HttpResponse;import org.apache.http.client.methods.HttpHead;import org.apache.http.impl.client.HttpClients;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.CommandLineRunner;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.zuul.EnableZuulProxy;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Import;import org.springframework.http.HttpStatus;import org.springframework.stereotype.Component;import org.springframework.web.servlet.config.annotation.CorsRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import com.netflix.zuul.filters.FilterRegistry;/** * Created by Jack on 2016/11/22. */@EnableZuulProxy@SpringBootApplication@Import({ XdiamondApplication.class})public class AppGateway { private static final Logger logger = LoggerFactory.getLogger(AppGateway.class); private static final String OAUTH_SERVER = "/oauthserver"; public static void main(String[] args) { SpringApplication.run(AppGateway.class, args); } @Bean public WebMvcConfigurer corsConfigurer() { // 允许跨域 return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedHeaders("origin, content-type, accept, x-requested-with") .allowedOrigins("*") .allowedMethods("POST", "DELETE", "PUT", "GET", "OPTIONS"); } }; } @Component public static class MyCommandLineRunner implements CommandLineRunner { @Autowired private UrlLimit urlLimit; public void run(String... args) throws Exception { initJavaFilters(); } private void initJavaFilters() { final FilterRegistry r = FilterRegistry.instance(); r.put("javaPreFilter", new ZuulFilter() { @Override public int filterOrder() { return 50000; } @Override public String filterType() { return "pre"; } public boolean shouldFilter() { return true; } public Object run() { try { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); String authType = request.getAuthType(); String contextPath = request.getContextPath(); Enumeration<String> headerNames = request.getHeaderNames(); String method = request.getMethod(); String pathInfo = request.getPathInfo(); String queryString = request.getQueryString(); String sessionId = request.getRequestedSessionId(); String remoteUser = request.getRemoteUser(); String uri = request.getRequestURI(); String url = request.getRequestURL().toString(); String servletPath = request.getServletPath(); String forwardedFor = RequestContext.getCurrentContext().getZuulRequestHeaders().get("x-forwarded-for"); String forwardedHost = RequestContext.getCurrentContext().getZuulRequestHeaders().get("x-forwarded-host"); String os = request.getParameter("os"); logger.info("running javaPreFilter"); logger.info("authType:" + authType + " contextPath:" + contextPath + " method:" + method + " pathInfo:" + pathInfo + " queryString:" + queryString + " sessionId:" + sessionId + " remoteUser:" + remoteUser+ " uri:" + uri + " servletPath:" + servletPath +" url:" + url + " headerNames:"+headerNames + " forwardedFor:"+forwardedFor+" forwardedHost:"+forwardedHost + " os:" + os); logger.info(RequestContext.getCurrentContext().getZuulRequestHeaders().toString()); if("OPTIONS".equals(method)) { //web端加head之前的探测请求 logger.info("web options request allow pass."); return null; } //通过计算次数来判断请求是否需要限制 if(urlLimit.needLimit(ctx)){ ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); logger.info("AuthorizePreFilter : the request had been limited"); }else { /**处理token的逻辑, 需要在url中加入oauthserver * 如:https://api.998jk.com/analyzer/brs/df/detail?type=1&userId=1657110 * 最终变为https://api.998jk.com/oauthserver/analyzer/brs/df/detail?type=1&userId=1657110 */ String newUrl = request.getScheme() + "://" + forwardedHost + OAUTH_SERVER + request.getRequestURI(); newUrl = "https://api.998jk.com/oauthserver/analyzer/brs/df/detail?type=1&userId=1657110"; logger.info("new url is :" + newUrl); int status = 0; try { HttpHead httpHead = new HttpHead(newUrl); httpHead.setHeader("Authorization",request.getHeader("Authorization")); httpHead.setHeader("Content-Type", "application/json"); HttpResponse returnResp = HttpClients.createDefault().execute(httpHead); status = returnResp.getStatusLine().getStatusCode(); } catch (IOException e) { logger.error("get oauthserver response error :" + e); } if(status == HttpServletResponse.SC_UNAUTHORIZED) { //token没有验证通过 ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); logger.info("AuthorizePreFilter : the request has no auth"); }else { logger.info("AuthorizePreFilter : the request is passed. and the status is :" + status); } } } catch(Exception e){ logger.info("error:", e); e.printStackTrace(); } return null; } }); } }}
用redis记录访问次数,进行限流
package zuul;import java.util.concurrent.TimeUnit;import javax.annotation.PostConstruct;import javax.servlet.http.HttpServletRequest;import org.apache.commons.lang.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.stereotype.Component;import com.netflix.zuul.context.RequestContext;import io.github.xdiamond.client.XDiamondConfig;import io.github.xdiamond.client.event.AllKeyListener;import io.github.xdiamond.client.event.ConfigEvent;/*** @author mhl* @version 创建时间:2017年3月8日* */@Componentpublic class UrlLimit { private static final Logger logger = LoggerFactory.getLogger(UrlLimit.class); @SuppressWarnings("rawtypes") @Autowired private RedisTemplate redisTemplate; @Autowired private XDiamondConfig xDiamondConfig; private static final String BLOCKED_IP = "blockedip"; private static final String LIMIT_COUNT = "limitCount"; private static final String REQUEST_TIME = "requestTime"; private static final String BLACK_LIST_TIME = "blackListTime"; private int limitCount = 5; //请求次数限制 private int requestTime = 1; //请求次数时限(秒) private int blackListTime = 7; //黑名单时长(天) /** * 通过请求次数来做限制 * mhl 2017年3月8日 */ public boolean needLimit(RequestContext context) { boolean result = false; HttpServletRequest request = context.getRequest(); String url = request.getRequestURI(); //访问url String forwardedFor = context.getZuulRequestHeaders().get("x-forwarded-for"); //IP if(forwardedFor == null) { return false; } if(redisTemplate.hasKey(forwardedFor)) { //黑名单需要限制 result = true; logger.info("[UrlLimit:calculate] the ip is in blackList"); }else { //检查访问频次 String key = forwardedFor + "_" + url; Long count = redisTemplate.opsForValue().increment(key, 1); if (count == 1) { requestTime = getConfigInt(REQUEST_TIME, 1); redisTemplate.expire(key, requestTime, TimeUnit.SECONDS); } limitCount = getConfigInt(LIMIT_COUNT, limitCount); if(count > limitCount) { result = true; logger.info("[UrlLimit:calculate] the ip called too many times: " + key); } } return result; } /** * 从配置文件读取ip 批量加入黑名单 * mhl 2017年3月9日 */ @PostConstruct public void batchAddBlacklist() { String blockedIps = getConfig(BLOCKED_IP); if(blockedIps == null || blockedIps.length() == 0) { logger.info("UrlLimit | blockedIps is null or has no data"); return; } String[] array = blockedIps.split(","); if(array.length > 0) { for (String string : array) { addBlacklist(string); } } logger.info("UrlLimit | blockedIps successed"); } public String getConfig(String key) { if(xDiamondConfig.getProperties() == null || xDiamondConfig.getProperties().isEmpty()) { init(); } return xDiamondConfig.getProperty(key); } public int getConfigInt(String key, int defaultInt) { int returnInt = defaultInt; if(xDiamondConfig.getProperties() == null || xDiamondConfig.getProperties().isEmpty()) { init(); } String keyStr = xDiamondConfig.getProperty(key); if (StringUtils.isNotBlank(keyStr)){ returnInt = Integer.parseInt(keyStr); } return returnInt; } /** * 初始化xDiamondConfig 并且增加监听事件 * mhl 2017年3月14日 */ private void init() { xDiamondConfig.init(); xDiamondConfig.addAllKeyListener(new AllKeyListener() { public void onConfigEvent(ConfigEvent configevent) { String key = configevent.getKey(); if(key.equals(BLOCKED_IP)) { String newBlackIpStr = configevent.getValue(); if(newBlackIpStr != null) { String[] array = newBlackIpStr.split(","); if(array.length > 0) { for (String string : array) { addBlacklist(string); } } } logger.info("UrlLimit | blackListListener successed"); }else if(key.equals(LIMIT_COUNT)) { limitCount = Integer.valueOf(configevent.getValue()); logger.info("UrlLimit | limitCount value changed " + limitCount); }else if(key.equals(REQUEST_TIME)) { requestTime = Integer.valueOf(configevent.getValue()); logger.info("UrlLimit | requestTime value changed " + requestTime); }else if(key.equals(BLACK_LIST_TIME)) { blackListTime = Integer.valueOf(configevent.getValue()); logger.info("UrlLimit | blackListTime value changed " + blackListTime); } } }); } /** * 手动添加黑名单 * mhl 2017年3月9日 * @param ip * @return */ public boolean addBlacklist(String key) { redisTemplate.opsForSet().add(key, key); String blackListTimeStr = getConfig(BLACK_LIST_TIME); if(blackListTimeStr != null) { blackListTime = Integer.valueOf(blackListTimeStr); } redisTemplate.expire(key, blackListTime, TimeUnit.DAYS); return true; } /** * 手动移除黑名单 * mhl 2017年3月9日 * @param ip * @return */ public boolean removeBlacklist(String key) { redisTemplate.delete(key); return true; } /** * 判断key是否在redis中 * mhl 2017年3月9日 * @param key * @return */ public boolean inRadis(String key) { return redisTemplate.hasKey(key); }}
阅读全文
0 0
- springcloud中zuul的应用
- springcloud-zuul路由的使用
- SpringCloud Zuul
- SpringCloud--zuul
- 【SpringCloud】(十五):Zuul的基本应用,反向代理和负载均衡
- SpringCloud(第 019 篇)Zuul 网关微服务的一些属性应用测试文章标题
- springcloud----Zuul动态路由
- SpringCloud: 路由网关(zuul)
- SpringCloud第六篇-Zuul
- SpringCloud网关Zuul
- 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)
- 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)
- 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)
- 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)
- 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)
- 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)
- 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)
- 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)
- 贪吃蛇小游戏
- [转载]Android任意位置获取应用Context
- json
- 显示文本中的部分信息
- Spring MVC的多视图解析器配置及与Freemarker的集成
- springcloud中zuul的应用
- 【C++】学习笔记四十二——函数重载
- oracle字符串截取函数substr
- Android Webview加载带视频的网页,遇到的问题。
- 成员变量,静态变量,静态块,静态方法执行顺序
- oracle的聚集函数wm_concat()和listagg()不适用时,自定义通用的聚集函数合并查询结果列
- history.back(-1)和history.go(-1)的区别
- BitmapShader实现圆形头像
- 【数据结构】二叉树前序、中序、后序遍历相互求法