在Spring Cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(zuul、Nginx),再到达服务网关(zuul集群),然后再到具体的服务。
简介
Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。zuul默认和Ribbon结合实现了负载均衡的功能。
创建工程
引入zuul依赖
1 2 3 4 5 6
   | <dependencies>     <dependency>         <groupId>org.springframework.cloud</groupId>         <artifactId>spring-cloud-starter-netflix-zuul</artifactId>     </dependency> </dependencies>
   | 
 
在启动类加上@EnableZuulProxy注解表示开启Zuul网关
在配置文件加上以下配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   | eureka:   client:     serviceUrl:       defaultZone: http://localhost:8761/eureka/ server:   port: 8769 spring:   application:     name: service-zuul zuul:   routes:     api-a:       path: /ribbon/**       serviceId: service-ribbon     api-b:       path: /feign/**       serviceId: service-feign
   | 
 
和其它module一样都注册到Eureka, 以/ribbon/开头的请求都转发给 service-ribbon服务,以/feign/开头的请求都转发给service-feign。
将以上服务全部开启,浏览器访问打开浏览器访问:http://localhost:8769/ribbon/hello?name=zuul
hello zuul,i am from port:8762
打开http://localhost:8769/feign/hello?name=zuul 也能看到zuul转发成功
过滤
zuul除了网关功能外还可以进行过滤,做一些校验。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
   | @Component public class MyZuulFilter extends ZuulFilter {
      /**      * 过滤器类型      * pre: 路由之前      * routing: 路由之时      * post: 路由之后      * error: 发送错误调用      */     @Override     public String filterType() {         return "pre";     }
      /**      * 过滤的顺序      */     @Override     public int filterOrder() {         return 0;     }
      /**      * 过滤条件      */     @Override     public boolean shouldFilter() {         return true;     }
      /**      * 过滤器具体逻辑      * @return      * @throws ZuulException      */     @Override     public Object run() throws ZuulException {
          RequestContext ctx = RequestContext.getCurrentContext();         HttpServletRequest request = ctx.getRequest();         Object accessToken = request.getParameter("token");
          if(accessToken == null) {             ctx.setSendZuulResponse(false);             ctx.setResponseStatusCode(401);             try {                 ctx.getResponse().getWriter().write("token is empty");             }catch (Exception e){                 e.printStackTrace();             }
              return null;         }
          return null;     } }
   | 
 
新建一个类继承ZuulFilter,run()方法里是执行过滤的逻辑,如果Filter类中的doFilter()方法,shouldFilter()方法是判断是否过滤,可以自定义过滤条件。
这个时候在浏览器输入 http://localhost:8769/ribbon/hello?name=zuul 可以看到
token is empty