• SpringCloud学习之Zuul


    1. zuul

      zuul是Netflix设计用来为所有面向设备、web网站提供服务的所有应用的门面,zuul可以提供动态路由、监控、弹性扩展、安全认证等服务,他还可以根据需求将请求路由到多个应用中。

    2. zuul的作用

        (1)要进入一个服务本身,很明显我们没有特别好的办法,直接输入IP地址+端口号,我们知道这样的做法很糟糕的,这样的做法大有问题,首先暴露了我们实体机器的IP地址,别人一看你的IP地址就知道服务部署在哪里,让别人很方便的进行攻击操作。

      (2)我们这么多服务,我们是不是要挨个调用它呀,我们这里假设做了个权限认证,我们每一个客户访问的都是跑在不同机器上的不同的JVM上的服务程序,我们每一个服务都需要一个服务认证,这样做比较繁琐。

        那么我们这时候面临着这两个极其重要的问题,这时我们就需要一个办法解决它们。首先,我们看IP地址的暴露和IP地址写死后带来的单点问题,我是不是对这么服务本身我也要动态的维护它服务的列表呀,我需要调用这服务本身,是不是也要一个负载均衡一样的玩意,

        还有关于IP地址暴露的玩意,我是不是需要做一个代理呀,像Nginx的反向代理一样的东西,还有这玩意上部署公共的模块,比如所有入口的权限校验的东西。因此我们现在需要Zuul API网关。它就解决了上面的问题,你想调用某个服务,它会给你映射,把你服务的IP地址映射成某个路径,你输入该路径,它匹配到了,它就去替你访问这个服务,它会有个请求转发的过程,像Nginx一样,服务机器的具体实例,它不会直接去访问IP,它会去Eureka注册中心拿到服务的实例ID,即服务的名字。我再次使用客户端的负载均衡ribbon访问其中服务实例中的一台。

        API网关主要为了服务本身对外的调用该怎么调用来解决的,还有解决权限校验的问题,你可以在这里整合调用一系列过滤器的,例如整合shiro,springsecurity之类的东西。

    Zuul可以通过加载动态过滤机制,从而实现以下各项功能:

      1.验证与安全保障: 识别面向各类资源的验证要求并拒绝那些与要求不符的请求。

      2.审查与监控: 在边缘位置追踪有意义数据及统计结果,从而为我们带来准确的生产状态结论。

      3.动态路由: 以动态方式根据需要将请求路由至不同后端集群处。

      4.压力测试: 逐渐增加指向集群的负载流量,从而计算性能水平。

      5.负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。

      6.静态响应处理: 在边缘位置直接建立部分响应,从而避免其流入内部集群。

      7.多区域弹性: 跨越AWS区域进行请求路由,旨在实现ELB使用多样化并保证边缘位置与使用者尽可能接近。

    3. 环境搭建

    新建SpringBoot工程,添加zuul依赖,如下所示:

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
                <version>1.3.5.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-zuul</artifactId>
                <version>1.3.5.RELEASE</version>
            </dependency>    

    接着在启动类上打上@EnableZuulProxy注解,修改配置文件

    server:
      port: 8000
    spring:
      application:
        name: api-geteway
    zuul:
      routes:
        #标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
        hello-service:
          #服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的IP,面向服务的路由了,给你选一个可用的出来,
          #这里zuul是自动依赖hystrix,ribbon的,不是面向单机
          path: /hello-service/**
          #这里一定要是你Eureka注册中心的服务的名称,是所以这里配置serviceId因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的IP了,
          #如url:http://localhost:8080/  这样的不好就是写死IP了,万一这IP挂了,这高可用性,服务注册那套东西就用不起来了
          serviceId: hello-service
    eureka:
      #客户端
      client:
        #注册中心地址
        service-url:
          defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/

        接着启动先前文章中的注册中心和两个hello-service服务提供者,测试它的请求转发功能,看他有没有轮询进入两个服务,可以看到zuul进行了请求分发了。它是根据你的服务名字hello-servie来映射到具体的机器上,这不就是一个反向代理的功能吗?zuul还能进行请求过滤,那么我们进行一下token校验来演示一下,首先我们需要先新建一个TokenFilter类来继承ZuulFilter这个类,实现它的四个接口,代码如下:

    public class TokenFilter extends ZuulFilter {
        // 四种类型:pre,routing,error,post
        // pre: 主要用在路由映射的阶段是寻找路由映射表的
        // routing: 具体的路由转发过滤器是在routing路由器,具体的请求转发的时候会调用
        // error: 一旦前面的过滤器出错了,会调用error过滤器。
        // post: 当routing,error运行完后才会调用该过滤器,是在最后阶段的
        @Override
        public String filterType() {
            return "pre";
        }
    
        // 自定义过滤器执行的顺序,数值越大越靠后执行,越小就越先执行
        @Override
        public int filterOrder() {
            return 0;
        }
    
        // 控制过滤器生效不生效,可以在里面写一串逻辑来控制
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        //执行过滤逻辑
        @Override
        public Object run() {
            RequestContext context = RequestContext.getCurrentContext();
            HttpServletRequest request = context.getRequest();
            String token = request.getParameter("token");
            if (token == null){
                context.setSendZuulResponse(false);
                context.setResponseStatusCode(401);
                context.setResponseBody("unAuthrized");
                return null;
            }
            return null;
        }
    }

    filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:

      1.pre:可以在请求被路由之前调用,用在路由映射的阶段是寻找路由映射表的

      2.route:在路由请求时候被调用,具体的路由转发过滤器是在routing路由器具体的请求转发的时候会调用

      3.error:处理请求时发生错误时被调用

      4.post:当routing,error运行完后才会调用该过滤器,是在最后阶段的

    这里声明一下zuul过滤器执行网络请求发生的异常,过滤器里面是不能直接将try-catch捕捉的异常抛出给页面的。应用程序抛出的异常是可以返回出的需解决办法就是在catch里面用context.set()方法返回给页面。如下:
    try{
        业务逻辑......
    }catch(Exception e){
            RequestContext context = RequestContext.getCurrentContext();
            context.set("error.status_code",401);
            context.set("error.exception",e);
            context.set("error.message","sfdfsdf");
    }

    接着,你还需要把这个过滤器加入spring中,让spring管理,代码如下:

    @SpringBootApplication
    @EnableZuulProxy
    public class ZuulApplication {
        public static void main(String[] args) {
            SpringApplication.run(ZuulApplication.class, args);
        }
      //将过滤器交给Spring管理
        @Bean
        public TokenFilter tokenFilter(){
            return new TokenFilter();
        }
    }

    映射规则,比方说

    zuul:
      routes:
    #标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
        hello-service:
    #服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的IP,面向服务的路由了,给你选一个可用的出来,
    #这里zuul是自动依赖hystrix,ribbon的,不是面向单机
          path: /hello-service/**
    #这里一定要是你Eureka注册中心的服务的名称,是所以这里配置serviceId因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的IP了,
    #如url:http://localhost:8080/  这样的不好就是写死IP了,万一这IP挂了,这高可用性,服务注册那套东西就用不起来了
          serviceId: hello-service
    
    zuul:
      routes:
        hello-service:
          path: /hello-service/ext/**
          serviceId: hello-service

        这里的两个zuul配置映射路径都有/hello-service/,可以看到/hello-service/**是包括/hello-service/ext/**的,这两个路径进行匹配的时候是按照yml中定义的顺序来匹配的。如果是application.properties格式的配置文件,它这个顺序是不能保证的,yml格式的配置文件是有顺序的,可以保证。如果我们想自定义一下匹配规则怎么办呢?那么我们就需要在启动类中定义一个bean,这个类就是决定你的路由的,如下:

     还有就是ignored-patterns:,如下:

    zuul:
      routes:
        # 标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
        hello-service:
          # 服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的IP,面向服务的路由了,给你选一个可用的出来,
          # 这里zuul是自动依赖hystrix,ribbon的,不是面向单机
          path: /hello-service/**
          # 这里一定要是你Eureka注册中心的服务的名称,是所以这里配置serviceId因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的IP了,
          # 如url:http://localhost:8080/  这样的不好就是写死IP了,万一这IP挂了,这高可用性,服务注册那套东西就用不起来了
          serviceId: hello-service
      ignored-patterns: /hello/**

        ignored-patterns:表示屏蔽掉/hello/**的路径,就算你/hello-service/hello/**也不行,照样屏蔽。这个配置我们可以进一步细化,比如说我不想给/hello接口路由,那我们可以按照上面方式配置,如果我们还想配置一个服务的前缀该怎么办?代码如下:

    zuul:
      routes:
        # 标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
        hello-service:
          # 服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的IP,面向服务的路由了,给你选一个可用的出来,
          # 这里zuul是自动依赖hystrix,ribbon的,不是面向单机
          path: /hello-service/**
          # 这里一定要是你Eureka注册中心的服务的名称,是所以这里配置serviceId因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的IP了,
          # 如url:http://localhost:8080/  这样的不好就是写死IP了,万一这IP挂了,这高可用性,服务注册那套东西就用不起来了
          serviceId: hello-service
      prefix: /api/**

        可以看到那么你访问的服务都必须要加/api/前缀,例如/api/hello-service/**,如果我们还想进行一个路径访问就跳转到我的本地,那该怎么办呢?我希望用户在访问/local时能够自动跳转到这个方法上来处理,那么此时我们需要用到Zuul的本地跳转,配置方式如下:

    zuul:
      prefix: /api
      ignored-patterns: /**/hello/**
      routes:
        local:
          path: /hello-service/**
          url: forward:/local

        我们常用的一些,对接springsecurity,或者是一些第三方组件,它们会获取你的一些cookie信息,那么Zuul网关为了安全起见,把你的cookie信息都给干掉了,这个是没办法去搞cookie的。它是默认干掉的。这里Zuul提供了zuul.sensitive-headers来给你搞这些cookie,header,这些信息不要进行过滤。控制你的敏感信息。默认情况下,敏感的头信息无法经过API网关进行传递,我们可以通过如下配置使之可以传递:

    zuul:
      routes:
        hello-service:
          path: /hello-service/**
          serviceId: hello-service
      sensitive-headers:   cookie,header之类额东西

    转自: https://www.cnblogs.com/huangjuncong/p/9060984.html

     

  • 相关阅读:
    字符串 CSV解析 表格 逗号分隔值 通讯录 电话簿 MD
    Context Application 使用总结 MD
    RxJava RxPermissions 动态权限 简介 原理 案例 MD
    Luban 鲁班 图片压缩 MD
    FileProvider N 7.0 升级 安装APK 选择文件 拍照 临时权限 MD
    组件化 得到 DDComponent JIMU 模块 插件 MD
    gradlew 命令行 build 调试 构建错误 Manifest merger failed MD
    protobuf Protocol Buffers 简介 案例 MD
    ORM数据库框架 SQLite 常用数据库框架比较 MD
    [工具配置]requirejs 多页面,多入口js文件打包总结
  • 原文地址:https://www.cnblogs.com/sunfie/p/12268804.html
Copyright © 2020-2023  润新知