zoukankan      html  css  js  c++  java
  • SpringCloud教程五:Zuul(路由+过滤)

    一、概述

    zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用。

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

    所有从设备或网站来的请求都会经过Zuul到达后端的Netflix应用程序。作为一个边界性质的应用程序,Zuul提供了动态路由、监控、弹性负载和安全功能。

    二、原理

    zuul的核心逻辑都是由一系列filter过滤器链实现的,但是filter的类型不同,执行的时机也不同,效果自然也不一样,主要特点如下:

    1. filter的类型:filter的类型,决定了它在整个filter链中的执行顺序,可能在端点路由前执行,也可能在端点路由时执行,还有可能在端点路由后执行,甚至是端点路由发生异常时执行。
    2. filter的执行顺序:同一种类型的filter,可以通过filterOrder()方法设置执行顺序,一般都是根据业务场景自定义filter执行顺序。
    3. filter执行条件:filter运行所需的标准,或条件。
    4. filter执行效果:符合某个filter执行条件,产生执行效果。

    zuul内部有一套完整的机制,可以动态读取编译运行filter机制,filter与filter之间不直接通信,在请求线程中会通过RequestContext来共享状态,它内部是用ThreadLocal实现的,例如HttpServletRequest、HttpServletResponse、异常信息等。

    zuul一共有4种不同的生命周期:

    1. pre:在zuul网关按照规则路由到下级服务之前执行,如果需要对请求进行预处理,可以使用这种类型的过滤器。如:认证鉴权,限流等。
    2. route:这种过滤器是zuul路由动作的执行者,是Apache HttpClient或Ribbon构建和发送原始HTTP请求的地方,现在也支持OKHTTP。
    3. post:这种过滤器是在端点请求完毕,返回结果或者发生异常后执行的filter。如果需要对返回的结果进行再次处理,可以在这种过滤中处理逻辑。
    4. error: 这种过滤器是在整个生命周期内,如果发生异常,就执行该filter,可以做全局异常处理。

    三、实践

    3.1路由演示

    这个实践代码基于:SpringCloud教程四。

    创建新的module,命名service-zuul,其pom.xml如下:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     4     <modelVersion>4.0.0</modelVersion>
     5 
     6     <groupId>com.wyma</groupId>
     7     <artifactId>service-zuul</artifactId>
     8     <version>0.0.1-SNAPSHOT</version>
     9     <packaging>jar</packaging>
    10 
    11     <name>service-zuul</name>
    12     <description>Demo project for Spring Boot</description>
    13 
    14     <parent>
    15         <groupId>org.springframework.boot</groupId>
    16         <artifactId>spring-boot-starter-parent</artifactId>
    17         <version>1.5.2.RELEASE</version>
    18         <relativePath/> <!-- lookup parent from repository -->
    19     </parent>
    20 
    21     <properties>
    22         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    23         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    24         <java.version>1.8</java.version>
    25     </properties>
    26 
    27     <dependencies>
    28         <dependency>
    29             <groupId>org.springframework.cloud</groupId>
    30             <artifactId>spring-cloud-starter-eureka</artifactId>
    31         </dependency>
    32         <dependency>
    33             <groupId>org.springframework.cloud</groupId>
    34             <artifactId>spring-cloud-starter-zuul</artifactId>
    35         </dependency>
    36         <dependency>
    37             <groupId>org.springframework.boot</groupId>
    38             <artifactId>spring-boot-starter-web</artifactId>
    39         </dependency>
    40 
    41         <dependency>
    42             <groupId>org.springframework.boot</groupId>
    43             <artifactId>spring-boot-starter-test</artifactId>
    44             <scope>test</scope>
    45         </dependency>
    46     </dependencies>
    47 
    48     <dependencyManagement>
    49         <dependencies>
    50             <dependency>
    51                 <groupId>org.springframework.cloud</groupId>
    52                 <artifactId>spring-cloud-dependencies</artifactId>
    53                 <version>Dalston.RC1</version>
    54                 <type>pom</type>
    55                 <scope>import</scope>
    56             </dependency>
    57         </dependencies>
    58     </dependencyManagement>
    59 
    60     <build>
    61         <plugins>
    62             <plugin>
    63                 <groupId>org.springframework.boot</groupId>
    64                 <artifactId>spring-boot-maven-plugin</artifactId>
    65             </plugin>
    66         </plugins>
    67     </build>
    68 
    69     <repositories>
    70         <repository>
    71             <id>spring-milestones</id>
    72             <name>Spring Milestones</name>
    73             <url>https://repo.spring.io/milestone</url>
    74             <snapshots>
    75                 <enabled>false</enabled>
    76             </snapshots>
    77         </repository>
    78     </repositories>
    79 
    80 
    81 </project>

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

     1 @EnableZuulProxy
     2 @EnableEurekaClient
     3 @SpringBootApplication
     4 public class ServiceZuulApplication {
     5 
     6     public static void main(String[] args) {
     7         SpringApplication.run(ServiceZuulApplication.class, args);
     8     }
     9 
    10 
    11 
    12 }

    配置文件application.yml如下:

     1 eureka:
     2   client:
     3     serviceUrl:
     4       defaultZone: http://localhost:8761/eureka/
     5 server:
     6   port: 8769
     7 spring:
     8   application:
     9     name: service-zuul
    10 zuul:
    11   routes:
    12     api-a:
    13       path: /api-a/**
    14       serviceId: service-ribbon
    15     api-b:
    16       path: /api-b/**
    17       serviceId: service-feign

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

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

    hello 51ma,i am from port:8763

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

    hello 51ma,i am from port:8763

    说明zuul起到路由的作用。

    3.2过滤演示

    添加MyFilter过滤器,如下:

     1 import com.netflix.zuul.ZuulFilter;
     2 import com.netflix.zuul.context.RequestContext;
     3 import org.slf4j.Logger;
     4 import org.slf4j.LoggerFactory;
     5 import org.springframework.stereotype.Component;
     6 
     7 import javax.servlet.http.HttpServletRequest;
     8 
     9 /**
    10  * Created by 51ma on 2019/5/13
    11  */
    12 @Component
    13 public class MyFilter extends ZuulFilter{
    14 
    15     private static Logger log = LoggerFactory.getLogger(MyFilter.class);
    16     @Override
    17     public String filterType() {
    18         return "pre";
    19     }
    20 
    21     @Override
    22     public int filterOrder() {
    23         return 0;
    24     }
    25 
    26     @Override
    27     public boolean shouldFilter() {
    28         return true;
    29     }
    30 
    31     @Override
    32     public Object run() {
    33         RequestContext ctx = RequestContext.getCurrentContext();
    34         HttpServletRequest request = ctx.getRequest();
    35         log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
    36         Object accessToken = request.getParameter("token");
    37         if(accessToken == null) {
    38             log.warn("token is empty");
    39             ctx.setSendZuulResponse(false);
    40             ctx.setResponseStatusCode(401);
    41             try {
    42                 ctx.getResponse().getWriter().write("token is empty");
    43             }catch (Exception e){}
    44 
    45             return null;
    46         }
    47         log.info("ok");
    48         return null;
    49     }
    50 }
    • filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
      • pre:路由之前
      • routing:路由之时
      • post: 路由之后
      • error:发送错误调用
    • filterOrder:过滤的顺序
    • shouldFilter:这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
    • run:过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。

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

    token is empty

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

    hello 51ma,i am from port:8763

    四、参考资料

    router_and_filter_zuul

    五、源码

    加入qq群:Spring全家桶技术交流①群196165973,免费获取源码。

  • 相关阅读:
    Codeforces Round #251 (Div. 2) A
    topcoder SRM 623 DIV2 CatAndRat
    topcoder SRM 623 DIV2 CatchTheBeatEasy
    topcoder SRM 622 DIV2 FibonacciDiv2
    topcoder SRM 622 DIV2 BoxesDiv2
    Leetcode Linked List Cycle II
    leetcode Linked List Cycle
    Leetcode Search Insert Position
    关于vim插件
    Codeforces Round #248 (Div. 2) B. Kuriyama Mirai's Stones
  • 原文地址:https://www.cnblogs.com/51ma/p/12881079.html
Copyright © 2011-2022 走看看