Zuul SpringCloud components of

Zuul is open source Netflix micro-services gateway, and Eureka, Ribbon, Hystrix and other components used in conjunction, Spring Cloud of Zuul have been integrated and enhanced, Zuul use the default HTTP client is Apache HTTPClient, can also be used RestClient or okhttp3.OkHttpClient . Zuul main function is to route forwarding and filters. Routing function is part of the micro-services, such as / demo / test forwarded to the demo service. zuul default and Ribbon combination to achieve a load balancing feature

This article describes the working principle and how to build zuul zuul services and introduce the relevant knowledge points

First, the working principle

Zuul core is a series of filters, which effect framework analogy Servlet Filter, or AOP. zuul to route requests to the user during the processing logic, these filter filtering process involved in a number, such as Authentication, Load Shedding etc.
zuul

Zuul use a range of different types of filters that allow us to quickly and flexibly to the function to the edge of our service. These filters can help us to perform the following functions

  • Authentication and security - to determine the authentication requirements for each resource and refused a request does not meet these requirements
  • Insight and monitoring - tracking meaningful data and statistics on the edge, in order to provide an accurate view of our production
  • Dynamic routing - The need to dynamically route the request to a different back-end cluster
  • Stress test - increasing traffic to measure the performance of the cluster.
  • Load Shedding - request for the allocation of capacity for each type of request and delete over the limit
  • Static response process - build some response directly at the edge, instead of forwarding them to the cluster.

Filter life cycle

time

Two, zuul components

  • zuul-core - zuul core library, compile and execute filter containing the core functionality .
  • zuul-simple-webapp - zuul Web application example shows how to use zuul-core building applications .
  • zuul-netflix--lib包,将其他NetflixOSS组件添加到Zuul中,例如使用功能区进去路由请求处理
  • zuul-netflix-webapp--webapp,它将zuul-core和zuul-netflix封装成一个简易的webapp工程包

三、搭建一个注册Eureka中心的Web服务

1、导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2、启动类

/**
 * @author Gjing
 */
@SpringBootApplication
@EnableEurekaClient
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

3、配置文件

server:
  port: 8090
spring:
  application:
    name: demo
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

4、提供接口外部访问

/**
 * @author Gjing
 **/
@RestController
public class TestController {

    @GetMapping("/test")
    public ResponseEntity test() {
        return ResponseEntity.ok("ok");
    }
}

四、搭建Zuul服务

这里不讲解Eureka服务搭建,不了解Eureka的可以查看这篇文章:SpringCloud组件之Eureka

1、导入zuul和eureka依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

2、启动类标注注解

/**
 * @author Gjing
 */
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}

3、配置文件

a、使用Eureka负载路由方式
server:
  port: 8080
spring:
  application:
    name: zuul
# 配置Eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
# 构建路由地址
zuul:
  routes:
    # 这里可以自定义
    demo2:
      # 匹配的路由规则
      path: /demo/**
      # 路由的目标服务名
      serviceId: demo

b、不使用eureka负载方式路由,采取请求地址路由

server:
  port: 8080
spring:
  application:
    name: zuul
# 配置eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
# 构建路由地址
zuul:
  routes:
    # 这里可以自定义
    demo2:
      # 匹配的路由规则
      path: /demo/**
      # 路由的目标服务名
      url: demo
# 关闭使用eureka负载路由
ribbon:
  eureka:
    enabled: false
# 如果不使用eureka的话,需要自己定义路由的那个服务的其他负载服务
demo:
  ribbon:
    # 这里写你要路由的demo服务的所有负载服务请求地址,本项目只启动一个,因此只写一个
    listOfServers: http://localhost:8090/
c、如果不想依赖于Eureka使用zuul,那么可使用以下配置方式
server:
  port: 8080
spring:
  application:
    name: zuul
# 构建路由地址
zuul:
  routes:
    # 这里可以自定义
    demo2:
      # 匹配的路由规则
      path: /demo/**
      # 路由的目标地址
      url: http://localhost:8090/

4、启动项目并访问即可

http://localhost:8080/demo/test

五、使用Zuul过滤器

为了让api网关组件可以被更方便的使用,它在http请求生命周期的各个阶段默认实现了一批核心过滤器,它们会在api网关服务启动的时候被自动加载和启动。我们可以在源码中查看和了解它们,它们定义与spring-cloud-netflix-core模块的org.springframework.cloud.netflix.zuul.filters包下。在默认启动的过滤器中包含三种不同生命周期的过滤器,这些过滤器都非常重要,可以帮组我们理解zuul对外部请求处理的过程,以及帮助我们在此基础上扩展过滤器去完成自身系统需要的功能

1、pre过滤器

  • ServletDetectionFilter

ServletDetectionFilter:它的执行顺序为-3,是最先被执行的过滤器。该过滤器总是会被执行,主要用来检测当前请求是通过Spring的DispatcherServlet处理运行的,还是通过ZuulServlet来处理运行的。它的检测结果会以布尔类型保存在当前请求上下文的isDispatcherServletRequest参数中,这样后续的过滤器中,我们就可以通过RequestUtils.isDispatcherServletRequest()和RequestUtils.isZuulServletRequest()方法来判断请求处理的源头,以实现后续不同的处理机制。一般情况下,发送到api网关的外部请求都会被Spring的DispatcherServlet处理,除了通过/zuul/路径访问的请求会绕过DispatcherServlet(比如之前我们说的大文件上传),被ZuulServlet处理,主要用来应对大文件上传的情况。另外,对于ZuulServlet的访问路径/zuul/,我们可以通过zuul.servletPath参数进行修改。

  • Servlet30WrapperFilter

它的执行顺序为-2,是第二个执行的过滤器,目前的实现会对所有请求生效,主要为了将原始的HttpServletRequest包装成Servlet30RequestWrapper对象。

  • FormBodyWrapperFilter

它的执行顺序为-1,是第三个执行的过滤器。该过滤器仅对两类请求生效,第一类是Context-Type为application/x-www-form-urlencoded的请求,第二类是Context-Type为multipart/form-data并且是由String的DispatcherServlet处理的请求(用到了ServletDetectionFilter的处理结果)。而该过滤器的主要目的是将符合要求的请求体包装成FormBodyRequestWrapper对象

  • DebugFilter

它的执行顺序为1,是第四个执行的过滤器,该过滤器会根据配置参数zuul.debug.request和请求中的debug参数来决定是否执行过滤器中的操作。而它的具体操作内容是将当前请求上下文中的debugRouting和debugRequest参数设置为true。由于在同一个请求的不同生命周期都可以访问到这二个值,所以我们在后续的各个过滤器中可以利用这二个值来定义一些debug信息,这样当线上环境出现问题的时候,可以通过参数的方式来激活这些debug信息以帮助分析问题,另外,对于请求参数中的debug参数,我们可以通过zuul.debug.parameter来进行自定义

  • PreDecorationFilter

执行顺序是5,是pre阶段最后被执行的过滤器,该过滤器会判断当前请求上下文中是否存在forward.do和serviceId参数,如果都不存在,那么它就会执行具体过滤器的操作(如果有一个存在的话,说明当前请求已经被处理过了,因为这二个信息就是根据当前请求的路由信息加载进来的)。而当它的具体操作内容就是为当前请求做一些预处理,比如说,进行路由规则的匹配,在请求上下文中设置该请求的基本信息以及将路由匹配结果等一些设置信息等,这些信息将是后续过滤器进行处理的重要依据,我们可以通过RequestContext.getCurrentContext()来访问这些信息。另外,我们还可以在该实现中找到对HTTP头请求进行处理的逻辑,其中包含了一些耳熟能详的头域,比如X-Forwarded-Host,X-Forwarded-Port。另外,对于这些头域是通过zuul.addProxyHeaders参数进行控制的,而这个参数默认值是true,所以zuul在请求跳转时默认会为请求增加X-Forwarded-*头域,包括X-Forwarded-Host,X-Forwarded-Port,X-Forwarded-For,X-Forwarded-Prefix,X-Forwarded-Proto。也可以通过设置zuul.addProxyHeaders=false关闭对这些头域的添加动作

2、route过滤器

  • RibbonRoutingFilter

它的执行顺序为10,是route阶段的第一个执行的过滤器。该过滤器只对请求上下文中存在serviceId参数的请求进行处理,即只对通过serviceId配置路由规则的请求生效。而该过滤器的执行逻辑就是面向服务路由的核心,它通过使用ribbon和hystrix来向服务实例发起请求,并将服务实例的请求结果返回

  • SimpleHostRoutingFilter

它的执行顺序为100,是route阶段的第二个执行的过滤器。该过滤器只对请求上下文存在routeHost参数的请求进行处理,即只对通过url配置路由规则的请求生效。而该过滤器的执行逻辑就是直接向routeHost参数的物理地址发起请求,从源码中我们可以知道该请求是直接通过httpclient包实现的,而没有使用Hystrix命令进行包装,所以这类请求并没有线程隔离和断路器的保护

  • SendForwardFilter

它的执行顺序是500,是route阶段第三个执行的过滤器。该过滤器只对请求上下文中存在的forward.do参数进行处理请求,即用来处理路由规则中的forward本地跳转装配

3、post过滤器

  • SendErrorFilter

它的执行顺序是0,是post阶段的第一个执行的过滤器。该过滤器仅在请求上下文中包含error.status_code参数(由之前执行的过滤器设置的错误编码)并且还没有被该过滤器处理过的时候执行。而该过滤器的具体逻辑就是利用上下文中的错误信息来组成一个forward到api网关/error错误端点的请求来产生错误响应

  • SendResponseFilter

它的执行顺序为1000,是post阶段最后执行的过滤器,该过滤器会检查请求上下文中是否包含请求响应相关的头信息,响应数据流或是响应体,只有在包含它们其中一个的时候执行处理逻辑。而该过滤器的处理逻辑就是利用上下文的响应信息来组织需要发送回客户端的响应内容

使用案例

如果前端发起请求没有带指定请求头将不进允许请求,如果需要读取cookie等敏感信息,要在配置文件中加入sensitive-headers:,下面有对该配置的详解

/**
 * @author Gjing
 **/
@Component
public class GlobalFilter extends ZuulFilter {
    @Override
    public String filterType() {
        //设置过滤类型
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        //设置过过滤器优先级
        return -4;
    }

    @Override
    public boolean shouldFilter() {
        //是否需要过滤
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        String token = request.getHeader("token");
        if (StringUtils.isEmpty(token)) {
            //返回错误信息
            context.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            context.setResponseBody(HttpStatus.UNAUTHORIZED.getReasonPhrase());
            context.setSendZuulResponse(false);
            return null;
        }
        return null;
    }
}

项目启动后如果访问不带Token请求头,将被拦截,返回Unauthorized

Zuul相关知识点

1、路由配置

zuul通过与eureka的整合,实现了对服务实例的自动化维护,所以使用服务路由配置的时候,不需要向传统路由配置方式那样为serviceId指定具体服务实例地址,只需要通过zuul.routes.<route>.pathzuul.routes.<route>.serviceId参数对的方式进行配置即可

zuul:
  routes:
    # 这里可以自定义
    demo2:
      # 匹配的路由规则
      path: /demo/**
      # 路由的目标服务名
      serviceId: demo

除了path和serviceId键值对的配置方式之外,还有一种简单的配置:zuul.routes.<serviceId>=<path>,其中用来指定路由的具体服务名,用来配置匹配的请求表达式

zuul:
  routes:
    demo: /demo/**

2、路径匹配

在zuul中,路由匹配的路径表达式采用ant风格定义

通配符 说明
匹配任意单个字符
* 匹配任意数量的字符
** 匹配任意数量的字符,支持多级目录

3、忽略表达式

通过path参数定义的ant表达式已经能够完成api网关上的路由规则配置功能,但是为了更细粒度和更为灵活地配置理由规则,zuul还提供了一个忽略表达式参数zuul.ignored-patterns。该参数可以用来设置不希望被api网关进行路由的url表达式

zuul:
  routes:
    demo:
      path: /demo/**
      serviceId: demo
  # 不路由demo2开头的任意请求
  ignored-patterns: /demo2/**

4、路由前缀

为了方便地为路由规则增加前缀信息,zuul提供了zuul.prefix参数来进行设置。比如,希望为网关上的路由规则增加/api前缀,那么我们可以在配置文件中增加配置:zuul.prefix=/api。另外,对于代理前缀会默认从路径中移除,我们可以通过设置zuul.strip-prefix=false(默认为true,默认为true时前缀生效,比如http://localhost:8080/api/demo/test)来关闭该移除代理前缀的动作

5、本地跳转

在zuul实现的api网关路由功能中,还支持forward形式的服务端跳转配置。实现方式非常简单,只需要通过使用path与url的配置方式就能完成,通过url中使用forward来指定需要跳转的服务器资源路径。

a、在zuul服务中添加一个接口
/**
 * @author Gjing
 **/
@RestController
public class HelloController {

    @GetMapping("/test/hello")
    public String test() {
        return "hello zuul";
    }
}
b、配置文件
zuul:
  routes:
    zuul-service:
      path: /api/**
      serviceId: forward:/test/

启动后访问http://localhost:8080/api/hello即可

6、cookie与头信息

By default, spring cloud zuul upon request routing, will filter out sensitive information request http header information, preventing them from being transmitted to the external server downstream. The default header information zuul.sensitiveHeaders sensitive parameter definition, including the default cookie, set-Cookie, authorization three attributes. So, do not pass when we used the default cookie in spring cloud zuul gateway in the development of web projects, which will lead to a common problem, if we want to use a spring security, shiro and other security framework to build web applications by when spring cloud zuul build a gateway for routing, because the cookie information can not be delivered, we will not achieve web application logon and authentication. To solve this problem, the following describes the two configurations

  • By setting a global parameter to override the default null value
zuul:
  routes:
    demo:
      path: /demo/**
      serviceId: demo
  # 允许敏感头,设置为空就行了
  sensitive-headers:
  • Parameter set by the specified route
zuul:
  routes:
    demo:
      path: /demo/**
      serviceId: demo
      # 将指定路由的敏感头设置为空
      sensitiveHeaders:

Articles on the introduction to it here, if you readers find where is wrong, give me Comments Oh, demo source code Address: SpringCloud-Demo

Guess you like

Origin yq.aliyun.com/articles/706982