精华内容
参与话题
问答
  • 简单的来说,我们把zuul这个项目启动起来,注册到eurake上,那么他就可以代理eurake上面的服务(默认),各种玩法听我细细道来。 源码下载路径在:https://download.csdn.net/download/qq_22075041/10869452,代码...

    简单的来说,我们把zuul这个项目启动起来,注册到eurake上,那么他就可以代理eurake上面的服务(默认),各种玩法听我细细道来。

    源码下载路径在:https://download.csdn.net/download/qq_22075041/10869452,代码参考microservice-gateway-zuul模块。

    首先加入zuul的依赖

    <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-zuul</artifactId>
    </dependency>
    <!--需要eurake的client依赖,因为要注册到eurake上-->
    <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>

    启动类上加一个注解@EnableZuulProxy,配置文件只需要把注册到eurake的配置做一下就可以了:

    server:
      port: 8040
    spring:
      application:
        name: microservice-gateway-zuul
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/
      instance:
        prefer-ip-address: true

    以上配置zuul默认代理eurake的所有服务,调用的时候以注册到eurake上的服务名。

    但是我觉得服务名太长了不好记,我要自定义,配置如下:

    zuul:
      routes:
      # 服务名 访问路径  注意/*和/**的区别:适配一层和适配多层
        microservice-provider-user: /user/** 

    如果我要忽略某几个微服务的代理呢?这样配(多个用逗号分开):

    zuul:
      ignored-services: microservice-provider-user,microservice-consumer-movie

    如果我只想代理指定的微服务呢?

    zuul:
      ignored-services: '*'   # 使用'*'可忽略所有微服务
      routes:
        microservice-provider-user: /user/**

    还可以这样玩:同时指定微服务的serviceId和对应路径path:

    zuul:
      routes:
        abc:                   # 该配置方式中,abc只是给路由一个名称,可以任意起名。
          service-id: microservice-provider-user
          path: /user/**              # service-id对应的路径

    玩法2:同时指定path和url

    zuul:
      routes:
        user-route:                   # 该配置方式中,user-route只是给路由一个名称,可以任意起名。
          url: http://localhost:8000/ # 指定的url
          path: /user/**              # url对应的路径。

    玩法2升级:同时指定path和URL,并且不破坏Zuul的Hystrix、Ribbon特性

    zuul:
      routes:
        user-route:
          path: /user/**
          service-id: microservice-provider-user
    ribbon:
      eureka:
        enabled: false    # 禁用掉ribbon的eureka使用。详见:http://cloud.spring.io/spring-cloud-static/Camden.SR3/#_example_disable_eureka_use_in_ribbon
    microservice-provider-user:
      ribbon:
        listOfServers: localhost:8000,localhost:8001

    为Zuul添加全局映射前缀: 应用场景比如项目根目录不是/ 而是/abc之类的

    zuul:
      prefix: /api
      strip-prefix: false # 默认为ture
      routes:
        microservice-provider-user: /user/**
    logging:
      level:
        com.netflix: DEBUG
        
    # 访问Zuul的/api/microservice-provider-user/1路径,请求将会被转发到microservice-provider-user的/api/1,,可以查看日志打印,有助于理解。

    为Zuul添加局部映射前缀,就是给某个服务添加:

    zuul:
      routes:
        microservice-provider-user: 
          path: /user/**
          strip-prefix: false
    logging:
      level:
        com.netflix: DEBUG
        
    # 这样访问Zuul的/user/1路径,请求将会被转发到microservice-provider-user的/user/1,可以查看日志打印,有助于理解。

    我要忽略某些敏感路径,这样配:

    zuul:
      ignoredPatterns: /**/admin/**   # 忽略所有包括/admin/的路径
      routes:
        microservice-provider-user: /user/**

    还有基于正则的玩法,削微有点不同,代码参考microservice-gateway-zuul-reg-exp模块:

    @SpringBootApplication
    @EnableZuulProxy
    public class ZuulApplication {
    
      @Bean
      public PatternServiceRouteMapper serviceRouteMapper() {
        // 调用构造函数PatternServiceRouteMapper(String servicePattern, String routePattern)
        // servicePattern指定微服务的正则
        // routePattern指定路由正则
        return new PatternServiceRouteMapper("(?<name>^.+)-(?<version>v.+$)", "${version}/${name}");
      }
    
      public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
      }
    }

    ====================================

    1.zuul现在使用的是HttpClient,可以使用其他的

    2.zuul还支持把一些敏感请求头文件不传到代理的服务上

    3.zuul服务自身转发,也可以配置。

    4.访问zuul的/route,可以看到zuul所有代理的情况

    5.@EnableZuulServer是一个zuul的轻量级自由注解,不带有负载,断路等功能

    =========================================

    接下里聊一下大文件上传,参考代码microservice-gateway-zuul-file-upload模块:

    # 上传大文件得将超时时间设置长一些,否则会报超时异常。以下几行超时设置来自http://cloud.spring.io/spring-cloud-static/Camden.SR3/#_uploading_files_through_zuul
    hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
    ribbon:
      ConnectTimeout: 3000
      ReadTimeout: 60000

    还有一个小技巧,我们上传一般使用的是springMVC,当我们使用zuul代理的时候,可以在代理路径前加上/zuul/*,则不会被springMVC上传的时候限制大小。

    =============================================

    zuul的fallback,参考代码microservice-gateway-zuul-fallback模块,其实就是自定义一个response

    package com.itmuch.cloud.study.fallback;
    
    import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.MediaType;
    import org.springframework.http.client.ClientHttpResponse;
    import org.springframework.stereotype.Component;
    
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.nio.charset.Charset;
    
    @Component
    public class UserFallbackProvider implements ZuulFallbackProvider {
      @Override
      public String getRoute() {
        // 表明是为哪个微服务提供回退
        return "microservice-provider-user";
      }
    
      @Override
      public ClientHttpResponse fallbackResponse() {
        return new ClientHttpResponse() {
          @Override
          public HttpStatus getStatusCode() throws IOException {
            // fallback时的状态码
            return HttpStatus.OK;
          }
    
          @Override
          public int getRawStatusCode() throws IOException {
            // 数字类型的状态码,本例返回的其实就是200,详见HttpStatus
            return this.getStatusCode().value();
          }
    
          @Override
          public String getStatusText() throws IOException {
            // 状态文本,本例返回的其实就是OK,详见HttpStatus
            return this.getStatusCode().getReasonPhrase();
          }
    
          @Override
          public void close() {
          }
    
          @Override
          public InputStream getBody() throws IOException {
            // 响应体
            return new ByteArrayInputStream("用户微服务不可用,请稍后再试。".getBytes());
          }
    
          @Override
          public HttpHeaders getHeaders() {
            // headers设定
            HttpHeaders headers = new HttpHeaders();
            MediaType mt = new MediaType("application","json", Charset.forName("UTF-8"));
            headers.setContentType(mt);
    
            return headers;
          }
        };
      }
    }
    

    ==================================

    定义zuul的过滤器:

    package com.itmuch.cloud.study.filters.pre;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.netflix.zuul.ZuulFilter;
    import com.netflix.zuul.context.RequestContext;
    
    public class PreRequestLogFilter extends ZuulFilter {
      private static final Logger LOGGER = LoggerFactory.getLogger(PreRequestLogFilter.class);
    
      @Override
      public String filterType() {
        return "pre";
      }
    
      @Override
      public int filterOrder() {
        return 1;
      }
    
      @Override
      public boolean shouldFilter() {
        return true;
      }
    
      @Override
      public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        PreRequestLogFilter.LOGGER.info(String.format("send %s request to %s", request.getMethod(), request.getRequestURL().toString()));
        return null;
      }
    }
    

    然后注入这个bean

    package com.itmuch.cloud.study;
    
    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 com.itmuch.cloud.study.filters.pre.PreRequestLogFilter;
    
    @SpringBootApplication
    @EnableZuulProxy
    public class ZuulApplication {
      public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
      }
    
      @Bean
      public PreRequestLogFilter preRequestLogFilter() {
        return new PreRequestLogFilter();
      }
    }

    zuul支持自定义Fifter,也有很多实现好的Fifter(在org.springframework.cloud.netflix.zuul.filters包下)。

    如果想禁用某一个Fifter,只需设置zuul.<SimpleClassName>.<filterType> .disable = true。例如,要禁用org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter 需设置 zuul.SendResponseFilter.post.disable = true。

    展开全文
  • 继上一篇讲述完Feign的详解和实例之后,本篇小熙将会讲述Zuul的详解和实例。 一. Zuul服务网关的介绍与用途 Zuul简介 Zuul相当于是第三方调用(app应用端和PC端)和服务提供方之间的防护门。作为前端服务(.....

    转载请注明出处:https://blog.csdn.net/weixin_41133233/article/details/85070323
    本文出自 程熙cjp 的博客

    继上一篇讲述完Feign的详解和实例之后,本篇小熙将会讲述Zuul的详解和实例。

    一. Zuul服务网关的介绍与用途

    1. Zuul简介

      Zuul相当于是第三方调用(app应用端和PC端)和服务提供方之间的防护门。作为前端服务(Edge Service也称边缘服务,前端服务的作用是对后端服务做必要的聚合和裁剪后暴露给外部不同的设备,如PC,Pad或者Phone),Zuul旨在实现动态路由,监控,弹性和安全性。它具备根据需求将请求路由到多个AWS自动弹性伸缩组的能力。

    2. Zuul能做什么

      Netflix API流量的量级和多样性随时可能导致生产环境故障而没有预警。因此需要一个系统能使我们迅速改变策略行为,以便应对各种情况。 Zuul使用一些不同类型的过滤器,使我们能够快速灵活地将功能应用于我们的前端服务。这些过滤器具有以下功能:

       (1)- 权限控制和安全性--为每个请求提供身份认证,并拒绝不满足条件的请求。		
       
       (2)- 预警和监控--跟踪前端有意义的请求和统计数据,以便我们准确了解生产环境运行状况。
       
       (3)- 动态路由--根据需求将请求动态地路由到不同的后端集群。
       
       (4)- 压力测试--逐渐增大到集群的流量,以便进行性能评估。
       
       (5)- 负载均衡--为每种类型的请求分配容量并丢弃超过限额的请求。
       
       (6)- 静态资源处理--直接在Zuul处理静态资源并响应,而并非转发这些请求到内部集群中。
       
       (7)- 多区域弹性--实现跨AWS区域请求路由,扩大了ELB的使用范围,并使前端服务更接近我们的成员。
      

      (翻译后,英文讲述来自GitHub:https://github.com/Netflix/zuul/wiki)

    二. 案例环境搭建

    这里小熙自己另起了一个Zuul项目,当然在原有的基础上搭建是更好的。

    项目源码在GitHub上:zuul项目源码

    1. 第一步

      点击Project
      创建项目

    2. 第二步

      点击next
      创建第二步

    3. 第三步

      根据自己喜好,修改Group和Artiface,之后点击next

      创建第三步

    4. 第四步

      这里还是可以自定义选择,下面小熙会附上pom文件,建议对比一下。
      创建第四步

    5. 第五步

      点击Finish

      创建第五步

    嗯,至此项目搭建骨架搭建完成了。如图:

    项目搭建成功图片

    接下来就是配置环境了。

    1. pom文件

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>com.chengxi</groupId>
          <artifactId>zuul-test</artifactId>
          <version>0.0.1-SNAPSHOT</version>
          <packaging>jar</packaging>
      
          <name>zuul-test</name>
          <description>Demo project for Spring Boot</description>
      
          <parent>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-parent</artifactId>
              <version>2.0.1.RELEASE</version>
              <relativePath/> <!-- lookup parent from repository -->
          </parent>
      
          <properties>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
              <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
              <java.version>1.8</java.version>
              <spring-cloud.version>Finchley.RC1</spring-cloud.version>
              <jjwt.version>0.7.0</jjwt.version>
              <joda-time.version>2.9.6</joda-time.version>
          </properties>
      
          <dependencies>
              <!--导入服务网关zuul-->
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
              </dependency>
      
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-test</artifactId>
                  <scope>test</scope>
              </dependency>
      
              <!--导入eureka客户端-->
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
              </dependency>
      
              <!--导入重试机制的坐标-->
              <dependency>
                  <groupId>org.springframework.retry</groupId>
                  <artifactId>spring-retry</artifactId>
              </dependency>
      
              <!--引入Hystrix依赖-->
              <dependency>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
              </dependency>
      
              <!--导入jwt相关依赖-->
              <dependency>
                  <groupId>io.jsonwebtoken</groupId>
                  <artifactId>jjwt</artifactId>
                  <version>${jjwt.version}</version>
              </dependency>
              <!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
              <dependency>
                  <groupId>joda-time</groupId>
                  <artifactId>joda-time</artifactId>
                  <version>${joda-time.version}</version>
              </dependency>
          </dependencies>
      
          <dependencyManagement>
              <dependencies>
                  <dependency>
                      <groupId>org.springframework.cloud</groupId>
                      <artifactId>spring-cloud-dependencies</artifactId>
                      <version>${spring-cloud.version}</version>
                      <type>pom</type>
                      <scope>import</scope>
                  </dependency>
              </dependencies>
          </dependencyManagement>
      
          <build>
              <plugins>
                  <plugin>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-maven-plugin</artifactId>
                  </plugin>
              </plugins>
          </build>
      
          <repositories>
              <repository>
                  <id>spring-milestones</id>
                  <name>Spring Milestones</name>
                  <url>https://repo.spring.io/milestone</url>
                  <snapshots>
                      <enabled>false</enabled>
                  </snapshots>
              </repository>
          </repositories>
      
      
      </project>
      
      

      这里的jwt将用于测试用户是否登录(具有颁发的token),是否有权限查询用户信息。

    2. yml配置文件

      server:
        port: 10012   # 端口号
      spring:
        application:
          name: zuul-service   # 网关服务名称
      zuul:
        prefix: /api   # 访问网关路径的前缀(在映射路径的前面,一般用于区别开发的版本)
        routes:
          zuul-service01:       # 随意写的区分不同映射服务器的名称(只是区分不同的映射服务器)
            path: /user-service-zuul/**    # 自定义映射服务器路径的名称(相当于key,外部访问这个地址会映射到下面的service-id这个value值。然后从eureka服务列表找到对应服务名称,进而负载均衡的请求一个服务器)
      #      url: http://127.0.0.1:8093  # 这是写的固定映射url,可代替service-id。但是不能实现服务器的负载均衡和高可用,因为总是访问同一服务器
            service-id: user-service     # eureka注册中心中要映射的服务名称,因为是双层map结构,所以可以实现负载均衡和高可用
          zuul-service02:               # 搭建另一个映射服务器,这里就简单的映射同一服务了。简单测试下而已
            path: /user-service-zuul-first/**
            service-id: user-service    # 映射服务器名称简单的使用上面的,仅供测试
      #  因为zuul是整合ribbon和hystrix的另一个客户端,所以我们需要自己导入spring-retry坐标,并且开启服务
        retryable: true
      #  配置zuul的连接时间,一般不需要配置
      #  host:
      #    max-per-route-connections:
      #    socket-timeout-millis:
      #    connect-timeout-millis:
      #  ignored-services: microservice-comsumer-movie-ribbon-withhystrix    # 这是表示某一个服务不允许代理,上面配置的是需要代理的
      eureka:
        client:
          registry-fetch-interval-seconds: 5    # 获取注册列表的周期
          service-url:
      #    eureka注册中心地址
            defaultZone: http://127.0.0.1:8090/eureka,http://127.0.0.1:8091/eureka,http://127.0.0.1:8092/eureka
        instance:
          prefer-ip-address: true   # 返回ip地址而不是hostname
          ip-address: 127.0.0.1      # 本机地址
      ribbon:
        ConnectTimeout: 250 # 连接超时时间(ms),默认值为250ms
        ReadTimeout: 2000 # 通信超时时间(ms),默认值为2000ms
        OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
        MaxAutoRetriesNextServer: 2 # 对同一服务不同实例重试次数(同一服务下集群个数的重试次数)
        MaxAutoRetries: 2 # 对同一实例重试的次数(单个集群节点服务重试的次数)
      # 开启熔断机制,超过六秒即开启熔断机制,网关内的时间排序:zuul的通信时间 > hystrix熔断时间 > retry重试时间
      hystrix:
        command:
          default:
            execution:
              isolation:
                thread:
                  timeoutInMilliseconds: 6000
      

      这里路由转服务的映射抒写是正常抒写,没有简写。下面会介绍简写方式。

    3. 修改启动配置类

      package com.chengxi;
      
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
      import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
      //@EnableZuulProxy简单理解为@EnableZuulServer的增强版,当Zuul与Eureka、Ribbon等组件配合使用时,我们使用@EnableZuulProxy。
      @SpringBootApplication
      @EnableZuulProxy            // 开启zuul的网关功能,他是一个组合注解,集成了eureka客户端注解。
      //@EnableDiscoveryClient      // 开启eureka客户端的消费者
      public class ZuulTestApplication {
      
          public static void main(String[] args) {
              SpringApplication.run(ZuulTestApplication.class, args);
          }
      }
      

      在这里小熙经过上网查询和实例测试,发现@EnableZuulProxy整合了@EnableDiscoveryClient注解(当然写上也可以)

      先贴上完整项目的注册列表图
      注册列表图片

      注意这里小熙考虑了电脑性能,只启动了一个Eureka,而消费者只是一个过渡替换成了用户,消费者和服务提供者的这种相互调用,可以理解为以后项目的服务间相互调用,feign还是能很优雅的提供restful的。

    4. 项目代码结构图(下面会附上代码)

      项目代码结构图

    5. config中的LoginFilter类

      package com.chengxi.config;
      
      import com.netflix.zuul.ZuulFilter;
      import com.netflix.zuul.context.RequestContext;
      import com.netflix.zuul.exception.ZuulException;
      import org.springframework.http.HttpStatus;
      import org.springframework.stereotype.Component;
      
      import javax.servlet.http.HttpServletRequest;
      
      /**
       *  编辑ZuulFilter自定义过滤器,用于校验登录
       *  重写zuulFilter类,有四个重要的方法
       *  1.- `shouldFilter`:返回一个`Boolean`值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
       *  2.- `run`:过滤器的具体业务逻辑。
       *  3.- `filterType`:返回字符串,代表过滤器的类型。包含以下4种:
       *      - `pre`:请求在被路由之前执行
       *      - `routing`:在路由请求时调用
       *      - `post`:在routing和errror过滤器之后调用
       *      - `error`:处理请求时发生错误调用
       *  4.- `filterOrder`:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高
       *
       *
       * @author chengxi
       * @date 2018/12/5 17:24
       */
      @Component
      public class LoginFilter extends ZuulFilter {
          @Override
          public String filterType() {
              // 登录校验的过滤级别,肯定是第一层过滤
              return "pre";
          }
      
          @Override
          public int filterOrder() {
              // 执行顺序为1,值越小执行顺行越靠前
              return 1;
          }
      
          @Override
          public boolean shouldFilter() {
              // 默认此类过滤器时false,不开启的,需要改为true
              return true;
          }
      
          /**
           *  登录校验过滤器,执行逻辑的方法
           * @return
           * @throws ZuulException
           */
          @Override
          public Object run() throws ZuulException {
              // 登录校验逻辑
              // 1)获取zuul提供的请求上下文对象(即是请求全部内容)
              RequestContext currentContext = RequestContext.getCurrentContext();
              // 2) 从上下文中获取request对象
              HttpServletRequest request = currentContext.getRequest();
              // 3) 从请求中获取token
              String token = request.getParameter("access-token");
              // 4) 判断(如果没有token,认为用户还没有登录,返回401状态码)
              if(token == null || "".equals(token.trim())){
                  // 没有token,认为登录校验失败,进行拦截
                  currentContext.setSendZuulResponse(false);
                  // 返回401状态码。也可以考虑重定向到登录页
                  currentContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
              }
      
              // 如果校验通过,可以考虑吧用户信息放入上下文,继续向后执行
              return null;
          }
      }
      
      

      这里代码都是固定的,未实现读取配置文件而形成的动态,下面会优化的。

    三. 测试运行

    完成以上给的,就可以实现简单的项目测试了。

    如图:

    1. 失败的(没有token被拦截)
      失败的

    2. 成功的

      成功访问

    由于篇幅过长,小熙将优化放在下一篇讲解吧。下篇小熙将会讲述Zuul网关优化之动态配置、jwt、rsa

    展开全文
  • 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul)

    万次阅读 多人点赞 2017-04-09 23:25:01
    在微服务架构中,需要几个关键的组件,服务注册与发现、服务消费、负载...客户端的请求首先经过负载均衡(zuul、Ngnix),再到达服务网关(zuul集群),然后再到具体的服务,服务统一注册到高可用的服务注册中心集群。

    转载请标明出处:
    https://www.fangzhipeng.com/springcloud/2017/06/05/sc05-zuul.html
    本文出自方志朋的博客

    个人博客纯净版:https://www.fangzhipeng.com/springcloud/2017/06/05/sc05-zuul.html

    最新Finchley版本,请访问:
    https://www.fangzhipeng.com/springcloud/2018/08/05/sc-f5-zuul.html
    或者
    http://blog.csdn.net/forezp/article/details/81041012

    在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、断路器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。一个简答的微服务系统如下图:

    在这里插入图片描述
    注意:A服务和B服务是可以相互调用的,作图的时候忘记了。并且配置服务也是注册到服务注册中心的。

    在Spring Cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(zuul、Ngnix),再到达服务网关(zuul集群),然后再到具体的服。,服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理(下一篇文章讲述),配置服务的配置文件放在git仓库,方便开发人员随时改配置。

    一、Zuul简介

    Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。zuul默认和Ribbon结合实现了负载均衡的功能。

    zuul有以下功能:

    • Authentication
    • Insights
    • Stress Testing
    • Canary Testing
    • Dynamic Routing
    • Service Migration
    • Load Shedding
    • Security
    • Static Response handling
    • Active/Active traffic management

    二、准备工作

    继续使用上一节的工程。在原有的工程上,创建一个新的工程。

    三、创建service-zuul工程

    其pom.xml文件如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    
    	<groupId>com.forezp</groupId>
    	<artifactId>service-zuul</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>jar</packaging>
    
    	<name>service-zuul</name>
    	<description>Demo project for Spring Boot</description>
    
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>1.5.2.RELEASE</version>
    		<relativePath/> <!-- lookup parent from repository -->
    	</parent>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    		<java.version>1.8</java.version>
    	</properties>
    
    	<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>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    		</dependency>
    	</dependencies>
    
    	<dependencyManagement>
    		<dependencies>
    			<dependency>
    				<groupId>org.springframework.cloud</groupId>
    				<artifactId>spring-cloud-dependencies</artifactId>
    				<version>Dalston.RC1</version>
    				<type>pom</type>
    				<scope>import</scope>
    			</dependency>
    		</dependencies>
    	</dependencyManagement>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    
    	<repositories>
    		<repository>
    			<id>spring-milestones</id>
    			<name>Spring Milestones</name>
    			<url>https://repo.spring.io/milestone</url>
    			<snapshots>
    				<enabled>false</enabled>
    			</snapshots>
    		</repository>
    	</repositories>
    
    
    </project>
    
    
    

    在其入口applicaton类加上注解@EnableZuulProxy,开启zuul的功能:

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

    加上配置文件application.yml加上以下的配置代码:

    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
    server:
      port: 8769
    spring:
      application:
        name: service-zuul
    zuul:
      routes:
        api-a:
          path: /api-a/**
          serviceId: service-ribbon
        api-b:
          path: /api-b/**
          serviceId: service-feign
    
    

    首先指定服务注册中心的地址为http://localhost:8761/eureka/,服务的端口为8769,服务名为service-zuul;以/api-a/ 开头的请求都转发给service-ribbon服务;以/api-b/开头的请求都转发给service-feign服务;

    依次运行这五个工程;打开浏览器访问:http://localhost:8769/api-a/hi?name=forezp ;浏览器显示:

    hi forezp,i am from port:8762

    打开浏览器访问:http://localhost:8769/api-b/hi?name=forezp ;浏览器显示:

    hi forezp,i am from port:8762

    这说明zuul起到了路由的作用

    四、服务过滤

    zuul不仅只是路由,并且还能过滤,做一些安全验证。继续改造工程;

    @Component
    public class MyFilter extends ZuulFilter{
    
        private static Logger log = LoggerFactory.getLogger(MyFilter.class);
        @Override
        public String filterType() {
            return "pre";
        }
    
        @Override
        public int filterOrder() {
            return 0;
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() {
            RequestContext ctx = RequestContext.getCurrentContext();
            HttpServletRequest request = ctx.getRequest();
            log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
            Object accessToken = request.getParameter("token");
            if(accessToken == null) {
                log.warn("token is empty");
                ctx.setSendZuulResponse(false);
                ctx.setResponseStatusCode(401);
                try {
                    ctx.getResponse().getWriter().write("token is empty");
                }catch (Exception e){}
    
                return null;
            }
            log.info("ok");
            return null;
        }
    }
    
    
    • filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
      • pre:路由之前
      • routing:路由之时
      • post: 路由之后
      • error:发送错误调用
    • filterOrder:过滤的顺序
    • shouldFilter:这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
    • run:过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。

    这时访问:http://localhost:8769/api-a/hi?name=forezp ;网页显示:

    token is empty

    访问 http://localhost:8769/api-a/hi?name=forezp&token=22 ;
    网页显示:

    hi forezp,i am from port:8762

    本文源码下载:
    https://github.com/forezp/SpringCloudLearning/tree/master/chapter5

    更多阅读

    史上最简单的 SpringCloud 教程汇总

    SpringBoot教程汇总

    Java面试题系列汇总

    五、参考资料:

    router_and_filter_zuul

    优秀文章推荐:

    SouthEast
    扫码关注公众号有惊喜

    (转载本站文章请注明作者和出处 方志朋的博客

    展开全文
  • zuul简介(一)

    2017-12-07 13:59:14
    zuul简介 Zuul 是在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门。 Zuul的内部实现结构图如下:   Zuul提供了一个框架,可以...
    zuul简介

    Zuul 是在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门。
    Zuul的内部实现结构图如下:

     Zuul提供了一个框架,可以对过滤器进行动态的加载,编译,运行。过滤器之间没有直接的相互通信。他们是通过一个RequestContext的静态类来进行数据传递的。RequestContext类中有ThreadLocal变量来记录每个Request所需要传递的数据。

    过滤器是由Groovy写成。这些过滤器文件被放在Zuul Server上的特定目录下面。Zuul会定期轮询这些目录。修改过的过滤器会动态的加载到Zuul Server中以便于request使用。

    下面有几种标准的过滤器类型:

    • PRE:这种过滤器在请求到达Origin Server之前调用。比如身份验证,在集群中选择请求的Origin Server,记log等。
    • ROUTING:在这种过滤器中把用户请求发送给Origin Server。发送给Origin Server的用户请求在这类过滤器中build。并使用Apache HttpClient或者Netfilx Ribbon发送给Origin Server。
    • POST:这种过滤器在用户请求从Origin Server返回以后执行。比如在返回的response上面加response header,做各种统计等。并在该过滤器中把response返回给客户。
    • ERROR:在其他阶段发生错误时执行该过滤器。
    • 客户定制:比如我们可以定制一种STATIC类型的过滤器,用来模拟生成返回给客户的response。

    过滤器的生命周期如下所示:


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

    • 验证与安全保障: 识别面向各类资源的验证要求并拒绝那些与要求不符的请求。
    • 审查与监控: 在边缘位置追踪有意义数据及统计结果,从而为我们带来准确的生产状态结论。
    • 动态路由: 以动态方式根据需要将请求路由至不同后端集群处。
    • 压力测试: 逐渐增加指向集群的负载流量,从而计算性能水平。
    • 负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。
    • 静态响应处理: 在边缘位置直接建立部分响应,从而避免其流入内部集群。
    • 多区域弹性: 跨越AWS区域进行请求路由,旨在实现ELB使用多样化并保证边缘位置与使用者尽可能接近。

    除此之外,Netflix公司还利用Zuul的功能通过金丝雀版本实现精确路由与压力测试。

     

    其核心代码ZuulServletFilter为:


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try {
            init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
            try {
                preRouting();
            } catch (ZuulException e) {
                error(e);
                postRouting();
                return;
            }
            
            // Only forward onto to the chain if a zuul response is not being sent
            if (!RequestContext.getCurrentContext().sendZuulResponse()) {
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
            
            try {
                routing();
            } catch (ZuulException e) {
                error(e);
                postRouting();
                return;
            }
            try {
                postRouting();
            } catch (ZuulException e) {
                error(e);
                return;
            }
        } catch (Throwable e) {
            error(new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_FROM_FILTER_" + e.getClass().getName()));
        } finally {
            RequestContext.getCurrentContext().unset();
        }
    }

    Zuul加载Groovy过滤器:
    package com.netflix.zuul.groovy;
    
    import com.netflix.zuul.DynamicCodeCompiler;
    import groovy.lang.GroovyClassLoader;
    import groovy.lang.GroovyObject;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.runners.MockitoJUnitRunner;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.io.File;
    import java.io.IOException;
    
    import static org.junit.Assert.*;
    import static org.mockito.Mockito.spy;
    
    /**
     * Groovy code compiler
     * User: mcohen
     * Date: 5/30/13
     * Time: 11:38 AM
     * To change this template use File | Settings | File Templates.
     */
    public class GroovyCompiler implements DynamicCodeCompiler {
    
        private static final Logger LOG = LoggerFactory.getLogger(GroovyCompiler.class);
    
        /**
         * Compiles Groovy code and returns the Class of the compiles code.
         *
         * @param sCode
         * @param sName
         * @return
         */
        @Override
        public Class compile(String sCode, String sName) {
            GroovyClassLoader loader = getGroovyClassLoader();
            LOG.warn("Compiling filter: " + sName);
            Class groovyClass = loader.parseClass(sCode, sName);
            return groovyClass;
        }
    
        /**
         * @return a new GroovyClassLoader
         */
        GroovyClassLoader getGroovyClassLoader() {
            return new GroovyClassLoader();
        }
    
        /**
         * Compiles groovy class from a file
         *
         * @param file
         * @return
         * @throws java.io.IOException
         */
        @Override
        public Class compile(File file) throws IOException {
            GroovyClassLoader loader = getGroovyClassLoader();
            Class groovyClass = loader.parseClass(file);
            return groovyClass;
        }
    
        @RunWith(MockitoJUnitRunner.class)
        public static class UnitTest {
            @Test
            public void testLoadGroovyFromString() {
    
                GroovyCompiler compiler = spy(new GroovyCompiler());
    
                try {
    
                    String code = "class test { public String hello(){return \"hello\" } } ";
                    Class clazz = compiler.compile(code, "test");
                    assertNotNull(clazz);
                    assertEquals(clazz.getName(), "test");
                    GroovyObject groovyObject = (GroovyObject) clazz.newInstance();
                    Object[] args = {};
                    String s = (String) groovyObject.invokeMethod("hello", args);
                    assertEquals(s, "hello");
    
    
                } catch (Exception e) {
                    assertFalse(true);
                }
    
            }
        }
    }



    参考:




    展开全文
  • 【网关----Zuul】基本原理及介绍

    万次阅读 2019-06-11 09:28:23
    一、zuul简介 1、作用 zuul使用一系列的filter实现以下功能 认证和安全 - 对每一个resource进行身份认证 追踪和监控 -实时观察后端微服务的TPS、响应时间,失败数量等准确的信息 日志 -记录所有请求的访问日志...
  • Zuul&&Kong

    千次阅读 2019-06-11 15:46:13
    网关(API Gateway )原由 之前学习分布式网站设计的时候,我们知道挡当应用体量提升的同时,我们的业务应用会逐步走向服务化,这样的架构适合大多数公司的演变,微服务的架构下,势必增加了op的工作量,每次新增一种...
  • Zuul的核心 Filter是Zuul的核心,用来实现对外服务的控制。Filter的生命周期有4个,分别是“PRE”、“ROUTING”、“POST”、“ERROR”。 Zuul大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命...
  • 一.... 1.1 什么是网关 API Gateway(APIGW / API 网关),顾名思义,是出现在系统边界上的一个面向API的、串行集中式的强管控服务,这里的边界是企业IT系统的边界,可以理解为企业级应用防火墙,主要起到隔离外部...
  • 网关zuul——过滤器

    2019-03-29 22:52:00
    网关——过滤器 从网关组件请求流程分析,可以看出网关的核心类为ZuulServlet,所有的请求都是走到这里来处理的! public void service(ServletRequest servletRequest, ServletResponse servletResponse) ...
  • ZUUL-API网关

    万次阅读 多人点赞 2018-10-10 08:16:33
    更多干货 分布式实战(干货) spring cloud 实战(干货) mybatis 实战(干货) spring boot 实战(干货) React 入门实战(干货) 构建中小型互联网企业架构(干货) ... ...
  • Zuul通常用法

    万次阅读 2018-05-29 10:50:11
    微服务架构体系中,通常一个业务系统会有很多的微服务,比如:OrderService、ProductService、UserService...,为了让调用更简单,一般会在这些服务前端再封装一层,类似下面这样:前面这一层俗称为“网关层”,其...
  • 在springcloud下使用websocket,前端框架使用vue ...若前端通过网关来连接websocket的服务,则会报404和一些跨域的问题。...注: 8604为webSocket服务的端口,9091为网关的端口 前端: !...后台: websocket配置: ...
  • Zuul网关

    千次阅读 2019-08-13 14:32:05
    一、Zuul网关简介 zuul是spring cloud中的微服务网关。 网关: 是一个网络整体系统中的前置门户入口。请求首先通过网关,进行路径的路由,定位到具体的服务节点上。 Zuul是一个微服务网关,首先是一个微服务。也是...
  • SpringCloud Zuul 网关搭建及配置

    千次阅读 热门讨论 2019-12-25 11:04:11
    一.Zuul网关 二.Zuul服务的前期准备 2.1 注册中心EurekaServer的搭建 2.2 EurekaService的搭建 三.Zuul服务搭建 五.Zuul的访问 六.Zuul的更多功能 前言:博主一直力求做到写博客尽量的详细来减少大家花在踩坑...
  • Zuul网关服务使用详解

    千次阅读 2017-12-05 14:47:38
    1.微服务架构所面临的问题?  1)针对某个功能,客户端在微服务架构的情况下需要请求多个模块接口 ... 1)客户端只需要知道网关而不需要知道具体模块的地址,所有服务由网关对外提供  2)身份认证类...
  • Zuul网关服务

    千次阅读 2019-06-15 00:21:40
    微服务调用过程 前面的博客文章已经介绍过spring cloud的服务的相关...这个就是spring cloud提供的网关网关维护着所有的微服务,客户端通过请求到网关,由网关分发到不同的微服务,这样客户端就只需要维护网关...
  • Zuul网关使用笔记

    2020-08-06 17:10:50
    文章目录Zuul介绍Pom 中引入包启动类中添加@EnableZuulProxy注解启用Zuul的API网关功能yml文件中配置相关属性信息路由映射规则传统路由实现方式面向服务的路由与传统路由相比,有外部请求到API网关的时候,面向服务...
  • Zuul是spring cloud中的微服务网关。网关: 是一个网络整体系统中的前置门户入口。请求首先通过网关,进行路径的路由,定位到... Zuul网关不是必要的。是推荐使用的。  使用Zuul,一般在微服务数量较多(多于10...
  • 微服务核心组件 Zuul 网关原理剖析

    万次阅读 2018-09-11 12:25:54
    在分布式的微服务系统中,系统被拆为了多套系统,通过zuul网关来对用户的请求进行路由,转发到具体的后台服务系统中。 本 Chat 主要内容如下: 服务网关演化历程。 Zuul 1.0 服务架构与源码剖析。 Zuul ...
  •  Zuul网关不是必要的。是推荐使用的。  使用Zuul,一般在微服务数量较多(多于10个)的时候推荐使用,对服务的管理有严格要求的时候推荐使用,当微服务权限要求严格的时候推荐使用。 一、Zuul网

空空如也

1 2 3 4 5 ... 20
收藏数 35,013
精华内容 14,005
关键字:

zuul