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,免费获取源码。

  • 相关阅读:
    ios开源项目2
    Cocoa 框架 For iOS(一) 框架的介绍
    iPhone开源项目大全
    8款iOS的日历开源代码
    二维码扫描工具和开发包 ZBar
    图文解释XCode常用快捷键的使用
    常用的iOS高效开源类库
    static_cast
    [转]SecureCRT rz 上传文件失败问题
    Linux中的EAGAIN含义
  • 原文地址:https://www.cnblogs.com/51ma/p/12881079.html
Copyright © 2011-2022 走看看