zoukankan      html  css  js  c++  java
  • Spring Cloud(八)Zuul路由网关

    1 概述

    1.1 什么是Zuul

    Zuul是所有设备和网站请求Netflix流应用程序后端的前门。作为一个边缘服务应用程序,Zuul旨在实现动态路由,监控,弹性和安全性。它还可以恰当的将请求路由到多个Amazon弹性集群中。

    1.2 为什么要建造Zuul

    大量不同的Netflix API流量有时会导致迅速而无预警地出现问题。我们需要一个能够迅速改变行为的系统,以应对这些情况。

    1.3 Zuul有哪些功能

    Zuul使用一系列不同类型的过滤器,使我们能够快速灵活地将这些功能应用于我们的边缘服务。这些过滤器可帮助我们执行以下功能:

    1. Authentication and Security(身份验证和安全性 ):识别每个资源的认证要求并拒绝不满足它们的请求。
    2. Insights and Monitoring(洞察和监控 ): 在边缘跟踪有意义的数据和统计数据,以便给我们一个准确的生产视图。
    3. Dynamic Routing(动态路由):根据需要动态地向不同的后端集群路由请求。
    4. Stress Testing(压力测试):逐渐向集群增加流量压力来评估性能。
    5. Load Shedding(甩负荷):为每种类型的请求分配容量,并删除超出限制的请求。
    6. Static Response handling(静态响应处理):直接在边缘建立一些响应,而不是将它们转发到内部集群。
    7. Multiregion Resiliency(多区域弹性):跨越AWS区域路由请求,以使我们ELB的使用多样化,并使我们的优势更靠近我们的成员。

    1.4 理解

    1. Zuul路由功能负责将外部的请求转发到具体的微服务实例上,是实现外部访问统一入口的基础。而过滤功能负责队请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。
    2. Zuul需要和Eureka整合,将Zuul注册为Eureka服务治理下的应用,同时从Eureka中获取其它微服务的消息,即以后对微服务的访问都通过Zuul跳转后获得。
    3. Zuul就像大楼的保安,你可以请他找人(代理),找的人在外面叫什么名字(路由),是否允许你进入大楼(过滤)。因为保安属于物业公司,所以保安要在物业公司注册,所获得的信息也来源于物业公司(与Eureka的关系)。

    2 Zuul路由功能

    2.1 创建zuul服务

    1. 导入依赖。
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
        </dependency>
    </dependencies>
    
    1. 配置文件。
    server:
      port: 9999
    spring:
      application:
        name: spring-cloud-zuul-gateway   #为这个服务取名,非常重要!!!!!
    eureka:
      client:
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
      instance:
        instance-id: zuul.com
        prefer-ip-address: true
    
    1. 修改hosts文件。
    127.0.0.0 zuul.com
    
    1. 创建主启动类,并加入@EnableZuulProxy注解。
    @SpringBootApplication
    @EnableZuulProxy
    public class SpringCloudZuulApplication9999 {
        public static void main(String[] args) {
            SpringApplication.run(SpringCloudZuulApplication9999.class, args);
        }
    }
    

    2.2 测试

    1. 依次启动uereka、一个provider、zuul服务,可以看到注册了两个微服务。
      在这里插入图片描述
    2. 通过http://[服务ip]:[服务端口]/[路径] 访问,访问成功。
      在这里插入图片描述
    3. 通过http://[网关服务ip]:[网关服务端口]/[微服务名称]/[路径] 访问,访问成功。
      在这里插入图片描述
      可以理解为,Zuul在微服务里找到了名为spring-cloud-provider的微服务,然后通过改为服务的访问路径访问服务

    2.3 路由访问映射规则

    2.3.1 修改配置文件

    server:
      port: 9999
    
    spring:
      application:
        name: spring-cloud-zuul-gateway   #为这个服务取名,非常重要!!!!!
    
    eureka:
      client:
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
      instance:
        instance-id: zuul.com
        prefer-ip-address: true
    zuul:
      ignored-services: spring-cloud-provider #禁止通过微服务名访问,可以使用通配符*,需要加“”转义
      prefix: /mysevice #访问前缀,如果没有该配置,则访问路径不能以/zuul/开头
      routes:
        spring-cloud-provider:  /myzuul/**   #routes参数格式为Map,前者是key 为被代理服务名-spring-cloud-provider,后者是value为代理路径-/myzuul/** ;可以配置多个服务代理
        #spring-cloud-provider1:  /myzuul1/** 
    

    2.3.2 修改后测试

    重行启动zuul服务,访问:http://zuul.com:9999/mysevice/myzuul/hello/jack
    在这里插入图片描述
    证明:只能通过http://[网关服务ip]:[网关服务端口]/[前缀][自己设置的路径]/[路径] 进行访问,不加前缀或者通过服务名访问都失败。

    3 自定义zuul过滤器

    3.1 编写代码

    //使该类成为配置类,注入spring容器
    @Configuration
    public class MyZuulFilter extends ZuulFilter {
    
        /**
         * pre:在请求路由之前执行过滤。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
         * route:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
         * post:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
         * error:在其他阶段发生错误时执行该过滤器。
         * 除了默认的过滤器类型,Zuul还允许我们创建自定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。
         * to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,
         * "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.
         * We also support a "static" type for static responses see  StaticResponseFilter.
         * Any filterType made be created or added and run by calling FilterProcessor.runFilters(type)
         *
         * @return A String representing that type
         */
        @Override
        public String filterType() {
            return "pre";
        }
    
        /**
         * 必须定义过滤器顺序,如果该过滤器的优先级不是很重要,过滤器顺序命令可以相同,过滤器命令不需要是连续的。
         * 命令从0,1,2...优先级依次降低
         * filterOrder() must also be defined for a filter. Filters may have the same  filterOrder if precedence is not
         * important for a filter. filterOrders do not need to be sequential.
         * @return the int order of a filter
         */
        @Override
        public int filterOrder() {
            return 0;
        }
    
        /**
         * 返回true run()方法将要执行,false将不执行,可以作为run() 方法执行开关。
         * a "true" return from this method means that the run() method should be invoked
         * @return true if the run() method should be invoked. false will not invoke the run() method
         */
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        /**
         * 可以自己编写任意的业务逻辑
         * if shouldFilter() is true, this method will be invoked. this method is the core method of a ZuulFilter
         * @return Some arbitrary artifact may be returned. Current implementation ignores it.
         */
        @Override
        public Object run() {
            System.out.println("shouldFilter() is true");
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();
            String requestURL = request.getRequestURL().toString();
            int index = requestURL.lastIndexOf('/')+1;
            String username = requestURL.substring(index);
            //判定长度小于三为非法用户名
            if (username.length() >2 ) {
                return true;
            }else{
                throw new RuntimeException("非法用户名,请检查!");
            }
        }
    }
    

    Zuul中默认实现了DebugFilter、StaticResponseFilter等过滤器,具体信息可以看源码,可以以以下方式禁用某种过滤器

    zuul:
        FormBodyWrapperFilter:
            pre:
                disable: true
    

    3.2 测试

    1. 访问:http://zuul.com:9999/mysevice/myzuul/hello/jack
      在这里插入图片描述
    2. 访问:http://zuul.com:9999/mysevice/myzuul/hello/ja
      在这里插入图片描述

    4 整合Feign Hystrix,通过客户端访问

    4.1 新建consumer hystrix zuul服务(复制consumer hystrix)

    改写feign调用接口。

    @FeignClient(name= "spring-cloud-zuul-gateway", fallback = HelloRemoteFallback.class)
    public interface HelloRemote {
        String ZUUL_URL_PREFIX = "/mysevice/myzuul";
        @RequestMapping(value = ZUUL_URL_PREFIX+"/hello/{name}")
        String hello(@RequestParam(value = "name") String name);
    }
    

    4.2 测试

    1. 依次启动uereka、provider、zuul、consumer hystrix zuul服务。
    2. 访问:http://localhost/consumer/hello/jack
      在这里插入图片描述
    3. 访问:http://localhost/consumer/hello/ja
      在这里插入图片描述

    5 Zuul 服务降级

    Zuul 是一个代理服务,如果被代理的服务突然宕机(如停掉provider 8001服务),那么zuul将会报错。但是consumer hystrix zuul服务已经有Feign降级服务,所以该服务不会报错,所有只有zuul报错,因此应该配置zuul的降级服务。

    5.1 新建MyZuulFallbackProvider类,并加入容器

    //注入容器
    @Component
    public class MyZuulFallbackProvider implements ZuulFallbackProvider {
        /**
         * 必须设置好处理的失败的服务路由
         * @return
         */
        @Override
        public String getRoute() {
            return "spring-cloud-provider";
        }
    
        @Override
        public ClientHttpResponse fallbackResponse() {
            return new ClientHttpResponse() {
    
                /**
                 * 服务调用失败后返回
                 * @return
                 * @throws IOException
                 */
                @Override
                public InputStream getBody() throws IOException {
                    return new ByteArrayInputStream("被代理服务故障,此结果由Zuul Gateway静态提供!".getBytes());
                }
    
                @Override
                public HttpHeaders getHeaders() {
                    HttpHeaders headers = new HttpHeaders() ;
                    headers.set("Content-Type", "text/html; charset=UTF-8");
                    return headers;
                }
    
                @Override
                public HttpStatus getStatusCode() throws IOException {
                    return HttpStatus.BAD_REQUEST;
                }
    
                @Override
                public int getRawStatusCode() throws IOException {
                    return HttpStatus.BAD_REQUEST.value();
                }
    
                @Override
                public String getStatusText() throws IOException {
                    return HttpStatus.BAD_REQUEST.getReasonPhrase();
                }
                @Override
                public void close() {
    
                }};
        }
    }
    

    5.2 测试

    1. 停掉provider 8001服务,访问:http://localhost/consumer/hello/jack
      在这里插入图片描述
    2. 访问:http://zuul.com:9999/mysevice/myzuul/hello/jack
      在这里插入图片描述
      看源码点这里
    只有把命运掌握在自己手中,从今天起开始努力,即使暂时看不到希望,也要相信自己。因为比你牛几倍的人,依然在努力。
  • 相关阅读:
    日期类和包装类
    集合——list
    数组
    多态小结
    一些概念性的知识点
    简单的图书管理系统
    一个小总结
    python-web自动化:上传操作
    python-web自动化:日期框操作
    python-web自动化:滚动条
  • 原文地址:https://www.cnblogs.com/freesky168/p/14358222.html
Copyright © 2011-2022 走看看