关于javascript:SpringCloud第十二篇Spring-Cloud-Gateway初探

4次阅读

共计 10387 个字符,预计需要花费 26 分钟才能阅读完成。

1. Zuul 和 Gateway 的恩怨情仇

1.1 背景

Zuul 是 Netflix 开源的一个我的项目,Spring 只是将 Zuul 集成在了 Spring Cloud 中。而 Spring Cloud Gateway 是 Spring Cloud 的一个子项目。

还有一个版本的说法是 Zuul2 的间断跳票和 Zuul1 的性能并不是很现实,从而催生了 Spring Cloud Gateway。(理解源码可 + 求求: 1791743380)

1.2 性能比拟

网上很多中央都说 Zuul 是阻塞的,Gateway 是非阻塞的,这么说是不谨严的,精确的讲 Zuul1.x 是阻塞的,而在 2.x 的版本中,Zuul 也是基于 Netty,也是非阻塞的,如果肯定要说性能,其实这个真没多大差距。

而官网出过一个测试项目,创立了一个 benchmark 的测试项目:spring-cloud-gateway-bench,其中比照了:

  • Spring Cloud Gateway
  • Zuul1.x
  • Linkerd

组件

RPS(request per second)

Spring Cloud Gateway

Requests/sec: 32213.38

Zuul

Requests/sec: 20800.13

Linkerd

Requests/sec: 28050.76

从后果可知,Spring Cloud Gateway 的 RPS 是 Zuul1.x 的 1.6 倍。

上面,咱们进入正题,开始聊聊 Spring Cloud Gateway 的一些事件。

2. Spring Cloud Gateway

Spring Cloud Gateway 是 Spring Cloud 的一个全新我的项目,该我的项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简略无效的对立的 API 路由治理形式。

Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,指标是代替 Netflix Zuul,其不仅提供对立的路由形式,并且基于 Filter 链的形式提供了网关根本的性能,例如:平安,监控 / 指标,和限流。

2.1 特色

  • 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
  • 动静路由
  • Predicates 和 Filters 作用于特定路由
  • 集成 Hystrix 断路器
  • 集成 Spring Cloud DiscoveryClient
  • 易于编写的 Predicates 和 Filters
  • 限流
  • 门路重写

2.2 术语

  • Route(路由):这是网关的根本构建块。它由一个 ID,一个指标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配。
  • Predicate(断言):这是一个 Java 8 的 Predicate。输出类型是一个 ServerWebExchange。咱们能够应用它来匹配来自 HTTP 申请的任何内容,例如 headers 或参数。
  • Filter(过滤器):这是 org.springframework.cloud.gateway.filter.GatewayFilter 的实例,咱们能够应用它批改申请和响应。

2.3 流程

[

](https://springcloud-oss.oss-c…

客户端向 Spring Cloud Gateway 发出请求。而后在 Gateway Handler Mapping 中找到与申请相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将申请发送到咱们理论的服务执行业务逻辑,而后返回。过滤器之间用虚线离开是因为过滤器可能会在发送代理申请之前(“pre”)或之后(“post”)执行业务逻辑。

3. 疾速上手

Spring Cloud Gateway 网关路由有两种配置形式:

  • 在配置文件 yml 中配置
  • 通过 @Bean 自定义 RouteLocator,在启动主类 Application 中配置

这两种形式是等价的,倡议应用 yml 形式进配置。

3.1 我的项目依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springcloud</groupId>
    <artifactId>gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

Spring Cloud Gateway 是应用 netty+webflux 实现因而不须要再引入 web 模块。### 3.2 配置文件

> ```yaml
> server:
>   port: 8080
> spring:
>   application:
>     name: api-gateway
>   cloud:
>     gateway:
>       routes:
>         - id: gateway-service
>           uri: https://blog.csdn.net
>           predicates:
>             - Path=/meteor_93

各字段含意如下:

  • id:咱们自定义的路由 ID,放弃惟一
  • uri:指标服务地址
  • predicates:路由条件,Predicate 承受一个输出参数,返回一个布尔值后果。该接口蕴含多种默认办法来将 Predicate 组合成其余简单的逻辑(比方:与,或,非)。

下面这段配置的意思是,配置了一个 id 为 gateway-service 的路由规定,当拜访地址 http://localhost:8080/meteor_93 时会主动转发到地址:http://localhost:8080/meteor_93。

3.3 测试

当初咱们启动服务,在浏览器中拜访地址 http://localhost:8080/meteor_93 时会展现页面展现如下:

[

](https://springcloud-oss.oss-c…

证实页面转发胜利。

3.4 另一种路由配置形式

转发性能同样能够通过代码来实现,咱们能够在启动类 GateWayApplication 中增加办法 customRouteLocator() 来定制转发规定。

package com.springcloud.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class GatewayApplication {public static void main(String[] args) {SpringApplication.run(GatewayApplication.class, args);
    }

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {return builder.routes()
                .route("path_route", r -> r.path("/meteor_93")
                        .uri("https://blog.csdn.net"))
                .build();}

咱们在 yaml 配置文件中登记掉相干路由的配置,重启服务,拜访链接:[http://localhost:8080/meteor\_93](http://localhost:8080/meteor_93),能够看到和下面一样的页面,证实咱们测试胜利。下面两个示例中 uri 都是指向了我的 CSDN 博客,在理论我的项目应用中能够将 uri 指向对外提供服务的我的项目地址,对立对外输入接口。以上便是 Spring Cloud Gateway 最简略的两个申请示例,Spring Cloud Gateway 还有更多实用的性能接下来咱们一一介绍。4\. 路由规定
--------

Spring Cloud Gateway 的性能很弱小,咱们仅仅通过 Predicates 的设计就可以看进去,后面咱们只是应用了 predicates 进行了简略的条件匹配,其实 Spring Cloud Gataway 帮咱们内置了很多 Predicates 性能。Spring Cloud Gateway 是通过 Spring WebFlux 的 HandlerMapping 做为底层反对来匹配到转发路由,Spring Cloud Gateway 内置了很多 Predicates 工厂,这些 Predicates 工厂通过不同的 HTTP 申请参数来匹配,多个 Predicates 工厂能够组合应用。### 4.1 Predicate 介绍

Predicate 来源于 Java 8,是 Java 8 中引入的一个函数,Predicate 承受一个输出参数,返回一个布尔值后果。该接口蕴含多种默认办法来将 Predicate 组合成其余简单的逻辑(比方:与,或,非)。能够用于接口申请参数校验、判断新老数据是否有变动须要进行更新操作。在 Spring Cloud Gateway 中 Spring 利用 Predicate 的个性实现了各种路由匹配规定,有通过 Header、申请参数等不同的条件来进行作为条件匹配到对应的路由。网上有一张图总结了 Spring Cloud 内置的几种 Predicate 的实现。[![SpringCloud 系列教程 | 第十二篇:Spring Cloud Gateway 初探](https://springcloud-oss.oss-cn-shanghai.aliyuncs.com/chapter12/spring-cloud-gateway3.png)

](https://springcloud-oss.oss-cn-shanghai.aliyuncs.com/chapter12/spring-cloud-gateway3.png)

说白了 Predicate 就是为了实现一组匹配规定,不便让申请过去找到对应的 Route 进行解决,接下来咱们接下 Spring Cloud GateWay 内置几种 Predicate 的应用。### 4.2 通过工夫匹配

Predicate 反对设置一个工夫,在申请进行转发的时候,能够通过判断在这个工夫之前或者之后进行转发。比方咱们当初设置只有在 2019 年 1 月 1 日才会转发到我的博客,在这之前不进行转发,我就能够这样配置:> ```yaml
> server:
>   port: 8080
> spring:
>   application:
>     name: api-gateway
>   cloud:
>     gateway:
>       routes:
>         - id: gateway-service
>           uri: https://www.baidu.com
>           order: 0
>           predicates:
>             - After=2019-01-01T00:00:00+08:00[Asia/Shanghai]

Spring 是通过 ZonedDateTime 来对工夫进行的比照,ZonedDateTime 是 Java 8 中日期工夫性能里,用于示意带时区的日期与工夫信息的类,ZonedDateTime 反对通过时区来设置工夫,中国的时区是:Asia/Shanghai。

After Route Predicate 是指在这个工夫之后的申请都转发到指标地址。下面的示例是指,申请工夫在 2019 年 1 月 1 日 0 点 0 分 0 秒之后的所有申请都转发到地址 https://blog.csdn.net。+08:00 是指工夫和 UTC 工夫相差八个小时,工夫地区为 Asia/Shanghai。

增加完路由规定之后,拜访地址 http://localhost:8080 会主动转发到 https://www.baidu.com。

Before Route Predicate 刚好相同,在某个工夫之前的申请的申请都进行转发。咱们把下面路由规定中的 After 改为 Before,如下:

server:
  port: 8080
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: gateway-service
          uri: https://www.baidu.com
          order: 0
          predicates:

就示意在这个工夫之前能够进行路由,在这工夫之后进行路由,批改完之后重启我的项目再次拜访地址 http://localhost:8080,页面会报 404 没有找到地址。除过在工夫之前或者之后外,Gateway 还反对限度路由申请在某一个时间段范畴内,能够应用 Between Route Predicate 来实现。> ```yaml
> server:
>   port: 8080
> spring:
>   application:
>     name: api-gateway
>   cloud:
>     gateway:
>       routes:
>         - id: gateway-service
>           uri: https://www.baidu.com
>           order: 0
>           predicates:
>             - Between=2019-01-01T00:00:00+08:00[Asia/Shanghai], 2019-07-01T00:00:00+08:00[Asia/Shanghai]

这样设置就意味着在这个时间段内能够匹配到此路由,超过这个时间段范畴则不会进行匹配。通过工夫匹配路由的性能很酷,能够用在限时流动的一些场景中。

4.3 通过 Cookie 匹配

Cookie Route Predicate 能够接管两个参数,一个是 Cookie name , 一个是正则表达式,路由规定会通过获取对应的 Cookie name 值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。

server:
  port: 8080
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: gateway-service
          uri: https://www.baidu.com
          order: 0
          predicates:

应用 curl 测试,命令行输出:

curl http://localhost:8080 –cookie “sessionId=test”


则会返回页面代码,如果去掉–cookie "sessionId=test",后盾汇报 404 谬误。### 4.4 通过 Header 属性匹配

Header Route Predicate 和 Cookie Route Predicate 一样,也是接管 2 个参数,一个 header 中属性名称和一个正则表达式,这个属性值和正则表达式匹配则执行。> ```yaml
> server:
>   port: 8080
> spring:
>   application:
>     name: api-gateway
>   cloud:
>     gateway:
>       routes:
>         - id: gateway-service
>           uri: https://www.baidu.com
>           order: 0
>           predicates:
>             - Header=X-Request-Id, \d+

应用 curl 测试,命令行输出:

curl http://localhost:8080  -H "X-Request-Id:88" 

则返回页面代码证实匹配胜利。将参数 -H “X-Request-Id:88″ 改为 -H “X-Request-Id:spring” 再次执行时返回 404 证实没有匹配。

4.5 通过 Host 匹配

Host Route Predicate 接管一组参数,一组匹配的域名列表,这个模板是一个 ant 分隔的模板,用. 号作为分隔符。它通过参数中的主机地址作为匹配规定。

server:
  port: 8080
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: gateway-service
          uri: https://www.baidu.com
          order: 0
          predicates:

应用 curl 测试,命令行输出:

> ```shell
> curl http://localhost:8080  -H "Host: www.baidu.com" 
> curl http://localhost:8080  -H "Host: md.baidu.com" 

经测试以上两种 host 均可匹配到 host_route 路由,去掉 host 参数则会报 404 谬误。

4.6 通过申请形式匹配

能够通过是 POST、GET、PUT、DELETE 等不同的申请形式来进行路由。

server:
  port: 8080
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: gateway-service
          uri: https://www.baidu.com
          order: 0
          predicates:
            - Method=GET

应用 curl 测试,命令行输出:

# curl 默认是以 GET 的形式去申请
curl http://localhost:8080

测试返回页面代码,证实匹配到路由,咱们再以 POST 的形式申请测试。

# curl 默认是以 GET 的形式去申请
curl -X POST http://localhost:8080

返回 404 没有找到,证实没有匹配上路由

4.7 通过申请门路匹配

Path Route Predicate 接管一个匹配门路的参数来判断是否走路由。

server:
  port: 8080
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: gateway-service
          uri: http://ityouknow.com
          order: 0
          predicates:

如果申请门路符合要求,则此路由将匹配,例如:/foo/1 或者 /foo/bar。应用 curl 测试,命令行输出:

> ```shell
> curl http://localhost:8080/foo/1
> curl http://localhost:8080/foo/xx
> curl http://localhost:8080/boo/xx
> ```

通过测试第一和第二条命令能够失常获取到页面返回值,最初一个命令报 404,证实路由是通过指定路由来匹配。### 4.8 通过申请参数匹配

Query Route Predicate 反对传入两个参数,一个是属性名一个为属性值,属性值能够是正则表达式。> ```yaml
> server:
>   port: 8080
> spring:
>   application:
>     name: api-gateway
>   cloud:
>     gateway:
>       routes:
>         - id: gateway-service
>           uri: https://www.baidu.com
>           order: 0
>           predicates:
>             - Query=smile
> ```

这样配置,只有申请中蕴含 smile 属性的参数即可匹配路由。应用 curl 测试,命令行输出:

curl localhost:8080?smile=x&id=2


通过测试发现只有申请汇总带有 smile 参数即会匹配路由,不带 smile 参数则不会匹配。还能够将 Query 的值以键值对的形式进行配置,这样在申请过去时会对属性值和正则进行匹配,匹配上才会走路由。> ```yaml
> server:
>   port: 8080
> spring:
>   application:
>     name: api-gateway
>   cloud:
>     gateway:
>       routes:
>         - id: gateway-service
>           uri: https://www.baidu.com
>           order: 0
>           predicates:
>             - Query=keep, pu.
> ```

这样只有当申请中蕴含 keep 属性并且参数值是以 pu 结尾的长度为三位的字符串才会进行匹配和路由。应用 curl 测试,命令行输出:

> ```shell
> curl localhost:8080?keep=pub
> ```

测试能够返回页面代码,将 keep 的属性值改为 pubx 再次拜访就会报 404, 证实路由须要匹配正则表达式才会进行路由。### 4.9 通过申请 ip 地址进行匹配

Predicate 也反对通过设置某个 ip 区间号段的申请才会路由,RemoteAddr Route Predicate 承受 cidr 符号 (IPv4 或 IPv6) 字符串的列表(最小大小为 1),例如 192.168.0.1/16 (其中 192.168.0.1 是 IP 地址,16 是子网掩码)。> ```yaml
> server:
>   port: 8080
> spring:
>   application:
>     name: api-gateway
>   cloud:
>     gateway:
>       routes:
>         - id: gateway-service
>           uri: https://www.baidu.com
>           order: 0
>           predicates:
>             - RemoteAddr=192.168.1.1/24
> ```

能够将此地址设置为本机的 ip 地址进行测试。> ```shell
> curl localhost:8080
> ```

如果申请的近程地址是 192.168.1.10,则此路由将匹配。### 4.10 组合应用

> ```yaml
> server:
>   port: 8080
> spring:
>   application:
>     name: api-gateway
>   cloud:
>     gateway:
>       routes:
>         - id: gateway-service
>           uri: https://www.baidu.com
>           order: 0
>           predicates:
>             - Host=**.foo.org
>             - Path=/headers
>             - Method=GET
>             - Header=X-Request-Id, \d+
>             - Query=foo, ba.
>             - Query=baz
>             - Cookie=chocolate, ch.p
>             - After=2018-01-20T06:06:06+08:00[Asia/Shanghai]

各种 Predicates 同时存在于同一个路由时,申请必须同时满足所有的条件才被这个路由匹配。

一个申请满足多个路由的谓词条件时,申请只会被首个胜利匹配的路由转发

以上就是明天的内容,咱们次要聊了 Gateway 的根底路由规定,前面的章节咱们接着聊更多的高级内容,比方:Filter、熔断和限流等。

正文完
 0