Spring Cloud Alibaba:Gateway网关 & 路由断言工厂

Spring Cloud Gateway

该项目提供了一个用于在Spring Webflux之上构建API网关的库。Spring Cloud Gateway旨在提供一种简单而有效的方式来路由到API并为它们提供交叉关注点,例如:安全监控弹性

Spring Cloud Gateway需要Spring BootSpring Webflux提供的Netty运行时环境。它不适用于传统的Servlet容器或将应用构建为WAR包。如果强制使用传统的Servlet来处理请求:
在这里插入图片描述
启动应用时会报错:
在这里插入图片描述

Spring Webflux is missing from the classpath, which is required for Spring Cloud Gateway at this time. Please add spring-boot-starter-webflux dependency.
Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. Please remove spring-boot-starter-web dependency.

classpath中缺少Spring Webflux,此时Spring Cloud Gateway需要它。请添加spring-boot-starter-webflux依赖项。
classpath上发现Spring MVC,此时与Spring Cloud Gateway不兼容。请删除spring-boot-starter-web依赖项。

重要概念:

  • 路由(Route):路由是网关的基本模块。它由ID、目标URIPredicate集合和Filter集合定义。如果聚合Predicate为真,则匹配路由。

  • 断言(Predicate):输入类型是Spring Framework ServerWebExchange。它允许开发人员匹配来自HTTP请求的任何内容,例如请求头或请求参数。
    在这里插入图片描述
    代码注释翻译插件Translation
    在这里插入图片描述

  • 过滤器(Filter):使用特定工厂构建的Spring Framework GatewayFilter实例,可以在发送代理请求之前或之后修改请求和响应。
    在这里插入图片描述

Spring Cloud Gateway特性:

  • 基于Spring Framework 5Project ReactorSpring Boot 2.0
  • 能够匹配任何请求属性的路由。
  • 特定于路由的断言和过滤器。
  • 集成Circuit Breaker
  • 集成Spring Cloud DiscoveryClient
  • 断言和过滤器易于编写。
  • 请求速率限制。
  • 路径重写。

Spring Cloud Gateway工作方式(图来自官网):

在这里插入图片描述
客户端向Spring Cloud Gateway发出请求。如果Gateway Handler Mapping确定请求与路由匹配,则将其发送到Gateway Web Handler。此处理程序通过特定于请求的过滤器链,将请求转换成代理请求。过滤器被虚线分隔的原因是过滤器可能在发送代理请求之前或之后执行逻辑。执行所有pre过滤器逻辑(作用于请求),然后发出代理请求。代理请求得到响应后,执行所有post过滤器逻辑(作用于响应)。

搭建工程

一个父module和两个子modulenacos module提供服务,gateway module实现网关)。

modulepom.xml

<?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>

    <groupId>com.kaven</groupId>
    <artifactId>alibaba</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <description>Spring Cloud Alibaba</description>
    <modules>
        <module>nacos</module>
        <module>gateway</module>
    </modules>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <spring-cloud-version>Hoxton.SR9</spring-cloud-version>
        <spring-cloud-alibaba-version>2.2.6.RELEASE</spring-cloud-alibaba-version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
    </parent>

    <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>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

nacos module

pom.xml

<?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>com.kaven</groupId>
        <artifactId>alibaba</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>nacos</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

application.yml

server:
  port: 8080

spring:
  application:
    name: nacos
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.1.197:9000

接口定义:

package com.kaven.alibaba.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MessageController {

    @GetMapping("/message")
    public String getMessage() {
        return "hello kaven, this is nacos";
    }
}

启动类:

package com.kaven.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

gateway module

pom.xml

<?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>com.kaven</groupId>
        <artifactId>alibaba</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>gateway</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
</project>

application.yml

server:
  port: 8085

spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: 192.168.1.197:9000
    gateway:
      routes:
        - id: nacos
          uri: http://localhost:8080
          predicates:
            - Path=/message

启动类:

package com.kaven.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

启动这两个moduleNacos的服务列表就会出现这两个服务。在这里插入图片描述

路由断言工厂

Spring Cloud Gateway匹配路由作为Spring Webflux HandlerMapping基础功能的一部分。Spring Cloud Gateway包括许多内置的路由断言工厂,这些路由断言工厂都匹配HTTP请求的不同属性,可以通过逻辑and来组合多个路由断言工厂。

After

After路由断言工厂接受一个日期时间,该断言匹配该日期时间之后的请求。生成这个日期时间的示例代码如下所示:

package com.kaven.alibaba;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Test {
    public static void main(String[] args) {

        ZonedDateTime nowDateTime = LocalDateTime.now()
                .atZone(ZoneId.systemDefault());
        System.out.println(nowDateTime);

        ZonedDateTime updateDateTime = LocalDateTime.now()
                .plusMonths(1)
                .minusDays(1).minusHours(1)
                .atZone(ZoneId.systemDefault());
        System.out.println(updateDateTime);

        ZonedDateTime hardCodeDateTime = LocalDateTime.
                of(2021, 12, 17, 18, 54, 17, 0)
                .atZone(ZoneId.systemDefault());
        System.out.println(hardCodeDateTime);
    }
}

输出:

2021-12-17T19:15:40.297+08:00[Asia/Shanghai]
2022-01-16T18:15:40.298+08:00[Asia/Shanghai]
2021-12-17T18:54:17+08:00[Asia/Shanghai]

表示年、月、日,时、分、秒、纳秒(不是毫秒)以及时区。

            - After=2021-12-17T19:30:00+08:00[Asia/Shanghai]

不在指定日期时间之后访问接口会直接响应404
在这里插入图片描述
指定日期时间之后,接口就可以正常访问了。
在这里插入图片描述

Before

Before路由断言工厂接受一个日期时间。此断言匹配在该日期时间之前发生的请求。由于和After路由断言工厂类似,这里就不再演示。

            - Before=2021-12-17T19:38:00.129+08:00[Asia/Shanghai]

Between

Between路由断言工厂接受两个日期时间。此断言匹配发生在datetime1之后和datetime2之前的请求。Between路由断言工厂与上面两种路由断言工厂类似,这里也不再演示。

            - Between=2021-12-17T19:38:00.129+08:00[Asia/Shanghai],2021-12-17T19:42:00.129+08:00[Asia/Shanghai]

datetime1参数指定的日期时间必须在datetime2参数指定的日期时间之前。在这里插入图片描述

Cookie

Cookie路由断言工厂接受两个参数,即Cookie名称和一个正则表达式。此断言匹配具有给定名称且值与正则表达式匹配的Cookie的请求。

            - Cookie=kaven,*kaven*

使用Postman来测试,请求没有Cookie
在这里插入图片描述
请求没有匹配的Cookie
在这里插入图片描述
请求有匹配的Cookie
在这里插入图片描述
路由的断言配置是一个List类型,因此可以配置多个断言,当聚合断言(聚合在信息科学中是指对有关的数据进行内容挑选、分析、归类,最后分析得到人们想要的结果,看完这篇博客就应该理解这里使用聚合这个词是比较合适的,因为断言中有逻辑and也有逻辑or)为真时,才匹配路由。

在这里插入图片描述

            - Cookie=username,.*kaven.*
            - Cookie=password,.*kaven.*

请求有所有匹配的Cookie
在这里插入图片描述
请求只有部分匹配的Cookie
在这里插入图片描述
所以,当断言列表中有互相矛盾的断言时,该路由就不可能匹配成功。

Header

Header路由断言工厂接受两个参数,Header名称和一个正则表达式。此断言与具有给定名称且值与正则表达式匹配的Header的请求匹配。

            - Header=gateway,.*kaven.*

在这里插入图片描述
在这里插入图片描述

Host

Host路由断言工厂接受一个参数:Host模式列表。该模式是一个Ant风格(请求路径的一种匹配方式)的模式,以.作为分隔符。此断言匹配Host满足列表中任意模式的请求。Ant通配符如下图所示:
在这里插入图片描述

            - Host=**.kaven.com,**.kaven.top

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
*?通配符这里就不演示了。

Method

Method路由断言工厂接受一个参数:要匹配的HTTP方法。

            - Method=GET

在这里插入图片描述
为了演示必须要满足指定的HTTP方法才能匹配路由,在nacos module中增加一个POST接口。

    @PostMapping("/message")
    public String updateMessage(String message) {
        return message;
    }

POST方法不匹配指定的GET方法,直接响应404
在这里插入图片描述
指定多个要匹配的HTTP方法,满足其中一个就可以匹配路由。

            - Method=GET,POST

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Path

Path路由断言工厂接受两个参数:一个Spring PathMatcher模式列表和一个可选的标志matchOptionalTrailingSeparator(此参数为true时,如果模式没有尾部斜杠,请求路径有尾部斜杠也能成功匹配,否则不能成功匹配,该参数默认为true)。该模式匹配也符合Ant风格,Ant通配符如下图所示:
在这里插入图片描述
为了方便演示,在nacos module中增加几个接口。

    @GetMapping("/kaven")
    public String kaven() {
        return "hello kaven";
    }

    @GetMapping("/kaven/1")
    public String kaven1() {
        return "hello kaven, this is 1";
    }


    @GetMapping("/kaven/1/2")
    public String kaven1_2() {
        return "hello kaven, this is 1/2";
    }
    
    @GetMapping("/itkaven")
    public String itkaven() {
        return "hello itkaven";
    }

    @GetMapping("/itkaven/1")
    public String itkaven1() {
        return "hello itkaven, this is 1";
    }
    
    @GetMapping("/itkaven/1/2")
    public String itkaven1_2() {
        return "hello itkaven, this is 1/2";
    }
            - Path=/kaven/{path},/itkaven/**

/itkaven/**表示路径是否以/itkaven开头(**表示后面有0个或者多个单位路径,*?通配符这里就不演示了),如果是则匹配。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
/kaven/{path}表示路径是否以/kaven开头并且后面有1个单位路径,如果是则匹配。
在这里插入图片描述
在这里插入图片描述
/kaven/2这个路径是匹配的,但nacos module中没有这个接口,仔细观察可以知道,/kaven/2路径的响应和/kaven路径的响应是不一样的(返回响应的主体不同,前者的响应是nacos module返回的,而后者的响应是gateway module返回的)。
在这里插入图片描述
在这里插入图片描述
路由的断言配置修改成如下所示,表示路径是否以/kaven开头并且后面有2个单位路径(以此类推)。

            - Path=/kaven/{path1}/{path2}

/kaven/1/2路径就可以匹配成功了。
在这里插入图片描述
matchOptionalTrailingSeparatorfalse

            - Path=/kaven/{path},false

路径有尾部斜杠不能成功匹配。
在这里插入图片描述
matchOptionalTrailingSeparatortrue(默认)。

            - Path=/kaven/{path},true

路径有尾部斜杠也能成功匹配。
在这里插入图片描述
如果模式有尾部斜杠,请求路径也必须有尾部斜杠,此时matchOptionalTrailingSeparator参数的值就不起作用了。

Query

Query路由断言工厂接受两个参数:必需的param和可选的regexp

            - Query=kaven

在这里插入图片描述

            - Query=kaven,.*itkaven.*

在这里插入图片描述
在这里插入图片描述

RemoteAddr

RemoteAddr路由断言工厂采用CIDR(用于解释IP地址的标准)表示的IPv4IPv6字符串列表(最少1个),例如192.168.1.199/24(其中192.168.1.199IP地址,24是子网掩码位数)。

           - RemoteAddr=192.168.1.1/24

在虚拟机中发送请求,虚拟机IP地址匹配。
在这里插入图片描述

            - RemoteAddr=192.168.2.1/24

虚拟机IP地址已经不匹配了。
在这里插入图片描述
Gateway网关和路由断言工厂就介绍到这里,如果博主有说错的地方或者大家有不同的见解,欢迎大家评论补充。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你可以通过 Spring Cloud Gateway 的 `RouteLocator` 接口来获取 `routes`。`RouteLocator` 是一个用于动态构建由规则的接口,它可以根据不同的条件来配置由信息。 在 Spring Cloud Gateway 中,可以通过实现 `RouteLocator` 接口的方式来自定义由规则。你可以创建一个类,实现 `RouteLocator` 接口,并在其中定义你的由规则。 下面是一个简单的示例: ```java import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class GatewayConfig { @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route(&quot;example_route&quot;, r -&gt; r.path(&quot;/example&quot;) .uri(&quot;http://example.com&quot;)) .route(&quot;another_route&quot;, r -&gt; r.host(&quot;*.example.org&quot;) .uri(&quot;http://example.org&quot;)) .build(); } } ``` 在上面的示例中,我们通过 `RouteLocatorBuilder` 来创建一个 `RouteLocator`,并定义了两个简单的由规则:一个是匹配 `/example` 径的请求转发到 `http://example.com`,另一个是匹配以 `.example.org` 结尾的主机名的请求转发到 `http://example.org`。 你可以根据自己的需求,定义不同的由规则,并在 `RouteLocator` 的实现类中返回相应的由信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ITKaven

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值