Spring Cloud Gateway 网关的初步认识和基本使用

Gateway 简单介绍

Gateway 是 Spring Cloud 官方推出的第二代网关框架,用于取代 Zuul 网关,基于 Netty 和 WebFlux 由于没有使用 Sevlet 容器,故不能打成 war 包, Gateway 只支持 SpringBoot2.X 及以上版本。

Gateway 三大核心概念

  • 路由 Route : 可以理解为设置请求转发到指定服务器的过程,是构建网关的基本模块,由 ID、目标 URI、断言集合和过滤器集合组成,如果断言为 true 则匹配路由。
  • 断言 Predicate : 是 Java 8 的一个函数式接口 predicate,可以用于 lambda 表达式和方法引用,输入类型是:Spring Framework ServerWebExchange,允许开发人员使用断言来匹配来自 HTTP 请求中携带的内容,例如请求头 headers 和参数 paramers。
  • 过滤 Filter : 是使用特定工厂构建的 Spring Framework GatewayFilter 实例,GatewayFilter 通过使用过滤器,对请求进行拦截,在请求路由前后作出修改操作。

Gateway 主要功能

  • 鉴权。
  • 限流。
  • 熔断。
  • 日志监控。

Gateway 工作流程图

了解过 Gateway 的小伙伴,相信对下面这张图都不陌生,此图大概描述了请求的处理原理,以及各个组件大致的位置,各个组件的作用如下:

  • Gateway Client:发送请求到 Spring Cloud Gateway 的客户端。
  • Gateway Handler Mapping:处理请求的组件,负责将请求映射到相应的处理器,根据请求的路由规则,从而选择对应的过滤器链。
  • Gateway Web Handler:实际处理请求的组件,会依次执行过滤器链,对请求进行处理。
  • Gateway Filter:过滤器,是由一系列过滤器组成过滤器链,每个过滤器执行一些特定业务逻辑,过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(pre)或之后(post)执行业务逻辑。
  • Proxied Service:被代理的服务,当执行完过滤器链之后会将请求转发到具体的目标服务。

Gateway 的核心逻辑是路由转发和执行过滤器链。

GatewayFilterFactory Gateway过滤器工厂

Spring提供了31种不同的路由过滤器工厂,具体如下:

名称 作用
AddRequestHeader 给当前请求添加一个请求头
AddRequestParameter 为原始请求添加请求参数
AddResponseHeader 给响应结果中添加一个响应头
DedupeResponseHeader 去掉重复请求头
Spring Cloud CircuitBreaker 断路器
FallbackHeaders 添加熔断后的异常信息到请求头
MapRequestHeader 将上游请求头的值赋值到下游请求头
PrefixPath 匹配的路由添加前缀
Preserve Host Header 保留原请求头
RequestRate Limiter 限制请求的流量
RedirectTo 重定向
RemoveRequestHeader 移除请求中的一个请求头
RemoveRequestParameter 移除请求参数
RewritePath 重写路径
RewriteLocationResponseHeader 重写响应头中 Location 的值
Rewrite ResponseHeader 重写响应头
SaveSession 向下游转发请求前前置执行 WebSession save 的操作
SecureHeaders 禁用默认值
SetRequestHeader 重置请求头
SetResponseHeader 修改响应头
SetStatus 修改响应的状态码
StripPrefix 对指定数量的路径前缀进行去除
Retry 重试
RequestSize 请求大小大于限制时,限制请求到达下游服务
SetRequestHostHeader 重置请求头值
ModifyRequestBody 修改请求体内容
ModifyResponse Body 修改响应体内容
Relay 将OAuth2访问令牌向下游转发到它所代理的服务
CacheRequestBody 在请求正文发送到下游之前缓存请求正文并从exchagne属性获取正文

Gateway 实战练习

  1. 新建 cloud-gateway 服务,引入 gateway 相关依赖,并将 cloud-gateway 注册到 Nacos,这里不在演示创建服务的过程,只展示引入的相关依赖。

pom.xml 文件如下:

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 https://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.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.user.service</groupId>
    <artifactId>user-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>user-service</name>
    <description>user-service</description>

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

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--引入 Nacos 支持-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2021.1</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-netflix-ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>2021.1</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-netflix-ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--引入 sentinel 支持-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2021.1</version>
        </dependency>

        <!--引入 OpenFeign 支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>3.0.1</version>
        </dependency>

        <!--引入 LoadBalancer 支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
            <version>3.0.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>3.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
            <version>3.0.1</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
            <version>1.8.0</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

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

</project>

could-gateway 服务 properties 文件如下:

java 复制代码
#服务名
spring.application.name=cloud-gateway
#端口
server.port=8888
#开启从注册中心动态创建路由的功能,利用微服务名称进行路由
spring.cloud.gateway.discovery.locator.enabled=true
#服务路由名小写
spring.cloud.gateway.discovery.locator.lower-case-service-id=true
#路由唯一标志
spring.cloud.gateway.routes[0].id = user-service
#路由指向目标 URL 服务名 客户端请求最终被转发到的微服务 推荐使用服务名称
spring.cloud.gateway.routes[0].uri = lb://user-service
#断言 以 /api/user 开头的请求都转发到 user-service 服务
spring.cloud.gateway.routes[0].predicates[0] = Path=/api/user/**
#过滤器 过滤掉 url 里的 /api/user 例如 http://ip:port/api/user/query-order 过滤后的地址是  http://ip:port/query-order
#如果不使用这个过滤器 直接在目标微服务的所有 api 路径前加上 /api/user  也是一样的
spring.cloud.gateway.routes[0].filters[0] = RewritePath=/api/user/(?<segment>.*), /$\{segment}
  1. 新建 user-service 服务,十分简单,这里不在演示,注意需要注册到 Nacos。

user-service 服务的测试代码如下:

java 复制代码
@Slf4j
@RestController
public class UserController {

    @GetMapping("/query-user")
    public String queryUser() {
        return "张飞";
    }

}
  1. cloud-gateway 和 user-service 注册在同一个 Nacos 的同一个 Namespace 的同一个 Group 上,如下图所示:

需要注意的是 cloud-gateway 和 user-service 在 Nacos 上的 Namespace、Group 必须保证一样,否则会无法调用,Gateway 会有如下日志:

java 复制代码
 2024-08-09 20:21:36.251  WARN 22008 --- [oundedElastic-6] o.s.c.l.core.RoundRobinLoadBalancer      : No servers available for service: user-service
  1. 通过 Gateway 调用验证

我们通过 Gateway 的 8888 端口调用到了 user-service 服务的 queryUser 接口,并正常响应了,结果符合预期。

本篇关于 Spring Cloud Gateway 网关的初步认识和基本使用就介绍到这里,希望可以帮助到有需要的小伙伴。

如有不正确的地方请各位指出纠正。

相关推荐
duration~31 分钟前
Maven随笔
java·maven
zmgst35 分钟前
canal1.1.7使用canal-adapter进行mysql同步数据
java·数据库·mysql
茶馆大橘38 分钟前
微服务系列六:分布式事务与seata
分布式·docker·微服务·nacos·seata·springcloud
跃ZHD44 分钟前
前后端分离,Jackson,Long精度丢失
java
blammmp1 小时前
Java:数据结构-枚举
java·开发语言·数据结构
暗黑起源喵1 小时前
设计模式-工厂设计模式
java·开发语言·设计模式
WaaTong1 小时前
Java反射
java·开发语言·反射
九圣残炎2 小时前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
wclass-zhengge2 小时前
Netty篇(入门编程)
java·linux·服务器
Re.不晚3 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea