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
原创粉丝点击