のZuul SpringCloudコンポーネント

Zuulは、オープンソースNetflixのマイクロサービスゲートウェイで、ユーレカ、リボン、Hystrixと組み合わせて用いられる他の成分、Zuulの春クラウドは統合され、強化されている、Zuulは、デフォルトのHTTPクライアントを使用してApacheのHTTPClientをされ、RestClientまたはokhttp3.OkHttpClientをも使用することができます。Zuul主な機能は、ルートの転送およびフィルタにあります。機能ルーティングすることは、デモ・サービスに転送/デモ/テストのマイクロサービスの一部です。負荷分散機能を実現するためzuulデフォルトとリボンの組み合わせ

この記事では、動作原理を説明し、zuul zuulサービスを構築し、関連する知識のポイントを紹介する方法

まず、動作原理

Zuulコアは、一連のフィルタ、エフェクトフレームワーク類似サーブレットフィルタ、またはAOPです。このような認証、等を負荷遮断などの処理ロジック、数に関与するこれらのフィルタのフィルタリング処理の間、ユーザにルート要求にzuul
zuul

Zuulは、当社のサービスのエッジに関数に私たちに迅速かつ柔軟にできるように異なるタイプのフィルタの範囲を使用します。これらのフィルタは、次の機能を実行するために私たちを助けることができます

  • 認証とセキュリティ - 各リソースの認証要件を決定し、要求を拒否したためには、これらの要件を満たしていません
  • インサイトとモニタリング - 当社の生産の正確なビューを提供するために、エッジに意味のあるデータと統計を追跡
  • 動的ルーティング - 異なるバックエンド・クラスタに動的にルート要求をする必要
  • ストレステスト - クラスターのパフォーマンスを測定するためにトラフィックを増やします。
  • 負荷制限 - 要求の種類ごとに容量の割り当て要求と制限を超えて削除
  • 静的応答プロセス - 代わりにクラスタに転送するの、エッジに直接いくつかの応答を構築します。

フィルタのライフサイクル

時間

二、zuul部品

  • zuulコア- zuulコアライブラリは、コア機能を含むフィルタをコンパイルし、実行します
  • zuul -シンプル- Webアプリケーション- zuul Webアプリケーションの例では、zuulコアアプリケーション構築を使用する方法を示しています
  • 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与头信息

デフォルトでは、リクエストルーティング時にスプリングクラウドzuulは、下流の外部サーバに送信されてからそれらを防止、機密情報の要求のHTTPヘッダ情報をフィルタリングします。デフォルトのヘッダ情報は、承認の3つの属性を、Cookieの設定されたデフォルトのクッキー、などの敏感なパラメータ定義を、zuul.sensitiveHeaders。我々は我々がすることで、Webアプリケーションを構築するために春のセキュリティ、史郎およびその他のセキュリティフレームワークを使用する場合、一般的な問題につながるWebプロジェクトの開発に春クラウドzuulゲートウェイのデフォルトのクッキーを使用する場合ので、合格しませんクッキー情報を配信することができないので、春の雲zuulは、ルーティングのためのゲートウェイを構築する際に、我々は、Webアプリケーションのログオンおよび認証を達成することはありません。この問題を解決するために、以下の二つの構成を説明します

  • デフォルトのNULL値を上書きするグローバルパラメータを設定することにより、
zuul:
  routes:
    demo:
      path: /demo/**
      serviceId: demo
  # 允许敏感头,设置为空就行了
  sensitive-headers:
  • 指定されたルートが設定したパラメータ
zuul:
  routes:
    demo:
      path: /demo/**
      serviceId: demo
      # 将指定路由的敏感头设置为空
      sensitiveHeaders:

ここでの紹介記事、間違っているどこ読者が見つけた場合、私はああ、デモのソースコードの住所コメント与える:SpringCloud-デモ

おすすめ

転載: yq.aliyun.com/articles/706982