SpringCloud Zuul

作者: BzCoder | 来源:发表于2018-09-12 02:38 被阅读3次

    1.微服务网关简介

    在微服务环境下,不同的服务有其不同的网络地址,若让客户端直接与各个微服务通信,客户端会多次请求不同微服务,存在跨域请求,处理相对复杂。此时我们就需要使用微服务网关。微服务网关介于服务端与客户端的中间层,所有外部服务请求都会先经过微服务网关,客户只能跟微服务网关进行交互,无需调用特定微服务接口,使得开发得到简化。

    2.Zuul简介

    Zuul 是开源的微服务网关,可与 Eureka、Ribbon、Hystrix 等组件配合使用,Zuul 它的核心是一系列过滤器,这些过滤器可完成下面功能:

    • 身份认证与安全:识别每个资源的验证要求,并拒绝那些要求不符合的请求
    • 审核与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图
    • 动态路由:动态的将请求路由到不同的后端集群
    • 压力测试:逐渐增加指向集群的流量,以了解性能
    • 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
    • 静态响应处理:在边缘位置直接建立部分响应,从而避免转发到内部集群
    • 多区域弹性:跨越 AWS Region 进行请求路由,实现 ELB 使用多样化,让系统边缘更贴近使用者

    3.配置

    Maven

    引入spring-cloud-starter-netflix-eureka-clientspring-cloud-starter-netflix-zuul

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

    添加注解

    @SpringBootApplication
    @EnableZuulProxy
    public class ApiGatewayApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ApiGatewayApplication.class, args);
        }
    }
    

    最后记得将他注册到注册中心上,就可以直接运行了,是不是非常简单呢?

    4.详细配置

    • 在配置文件中加入management.endpoints.web.exposure.include=*可以通过访问actuator/routes来查看路由情况。
    • 配置需要路由的路径和忽略的路径。配置路由格式为【 服务名称:路径 】,假如要配置product服务:
      routes:
        product: /myProduct/**
      ignored-patterns:
       - /**/product/**
    
    • 跨域
      假如服务中单个接口需要跨域,只要在方法上添加@CrossOrigin(allowCredentials = "true")注解。
      假如需要对多个接口做跨域,可以在Zuul中做配置。
    /**
     * 跨域配置
     *
     * @author BaoZhou
     * @date 2018/9/13
     */
    @Configuration
    public class CorsConfig {
        @Bean
        public CorsFilter corsFilter() {
            final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            final CorsConfiguration config = new CorsConfiguration();
    
    
            config.setAllowCredentials(true);
            //可以写域名,比如http://www.baidu.com
            config.setAllowedOrigins(Arrays.asList("*"));
            config.setAllowedHeaders(Arrays.asList("*"));
            config.setAllowedMethods(Arrays.asList("GET","POST"));
            config.setMaxAge(300L);
            source.registerCorsConfiguration("/**", config);
            return new CorsFilter();
        }
    }
    
    • 默认经过路由不转发cookie等信息,我们可以在配置文件中加sensitiveHeaders来开启
    zuul:
      routes:
        product: /myProduct/**
      ignored-patterns:
         - /**/product/**
      sensitiveHeaders:
    
    • 配合SpringBus动态配置Zuul。需要添加配置项
     @ConfigurationProperties("zuul")
        @RefreshScope
        public ZuulProperties zuulProperties() {
            return new ZuulProperties();
        }
    

    Zuul有四种过滤器:

    • PRE:在请求被路由之前调用,可用于身份验证、集群中选择请求的微服务、记录调试信息等,可以用于限流,鉴权,参数校验调整,请求转发。
    • ROUTING:请求路由到微服务时执行,用于构建发送给微服务的请求,使用 HttpClient 或 Ribbon 请求微服务。
    • POST:在路由到微服务后执行,可用来为响应添加 Header,收集统计信息和指标、将相应从微服务发送给客户端等,可以用于统计,日志等。
    • ERROR:在其他阶段发生错误时执行该过滤器。

    限流 令牌桶

    public class RateLimitFilter extends ZuulFilter {
        private static final RateLimiter RATE_LIMITER =RateLimiter.create(100);
        @Override
        public String filterType() {
            return PRE_TYPE;
        }
    
        @Override
        public int filterOrder() {
            return SERVLET_DETECTION_FILTER_ORDER - 1;
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() throws ZuulException {
            if(!RATE_LIMITER.tryAcquire())
            {
                throw new RateLimitException();
            }
            return null;
        }
    }
    

    添加请求头

    public class AddResponseHeaderFilter extends ZuulFilter {
        @Override
        public String filterType() {
            return POST_TYPE;
        }
    
        @Override
        public int filterOrder() {
            return SEND_RESPONSE_FILTER_ORDER - 1;
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() throws ZuulException {
            RequestContext requestContext = RequestContext.getCurrentContext();
            HttpServletResponse response = requestContext.getResponse();
            response.setHeader("X-Foo",UUID.randomUUID().toString());
            return null;
        }
    }
    

    校验请求参数

    public class TokenFilter extends ZuulFilter {
    
        /**
         * 指定过滤器类型
         * 可以从常量中去选取
         * public static final String ERROR_TYPE = "error";
         * public static final String POST_TYPE = "post";
         * public static final String PRE_TYPE = "pre";
         * public static final String ROUTE_TYPE = "route";
         *
         * @return
         */
        @Override
        public String filterType() {
            return PRE_TYPE;
        }
    
        /**
         * 设置过滤器优先级,数字越小优先级越高
         * public static final int DEBUG_FILTER_ORDER = 1;
         * public static final int FORM_BODY_WRAPPER_FILTER_ORDER = -1;
         * public static final int PRE_DECORATION_FILTER_ORDER = 5;
         * public static final int RIBBON_ROUTING_FILTER_ORDER = 10;
         * public static final int SEND_ERROR_FILTER_ORDER = 0;
         * public static final int SEND_FORWARD_FILTER_ORDER = 500;
         * public static final int SEND_RESPONSE_FILTER_ORDER = 1000;
         * public static final int SIMPLE_HOST_ROUTING_FILTER_ORDER = 100;
         * public static final int SERVLET_30_WRAPPER_FILTER_ORDER = -2;
         * public static final int SERVLET_DETECTION_FILTER_ORDER = -3;
         *
         * @return
         */
        @Override
        public int filterOrder() {
            return PRE_DECORATION_FILTER_ORDER - 1;
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        /**
         * 处理逻辑
         * @return
         * @throws ZuulException
         */
        @Override
        public Object run() throws ZuulException {
            RequestContext requestContext = RequestContext.getCurrentContext();
            HttpServletRequest request = requestContext.getRequest();
            //从Url参数里获取token,也可以从cookie,header里获取
            String token = request.getParameter("token");
            if(StringUtils.isEmpty(token))
            {
                requestContext.setSendZuulResponse(false);
                requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            }
            return null;
        }
    }
    

    一般在run里写逻辑,shouldFilter里写是否需要过滤来保证逻辑的清晰。

    文中很多内容引用自https://www.jianshu.com/p/29e9c91e3f3e,特别感谢!

    相关文章

      网友评论

        本文标题:SpringCloud Zuul

        本文链接:https://www.haomeiwen.com/subject/seoygftx.html