【SpringCloud】6.0 网关控制Gateway

微服务架构

  • SpringCloud
    服务注册发现:Nacos
    服务限流降级:Sentinel
    分布配置中⼼:Nacos
    分布式事务保证数据一致性:Seata
    分布式定时任务:Spring Scheduling Tasks
    服务⽹关:SpringCloud Gateway
    异步消息削峰填谷:RocketMQ
    服务之间调⽤:OpenFeign、Ribbon
    链路追踪:Sleuth+Zipkin

技术栈版本控制

序号 名称 版本 用途 备注
1 openJDK 21 Java JDK
2 postgresSQL 17.4 基础数据库
3 Maven 3.9.9 Java第三方依赖包管理工具
4 springboot 3.4.3 Java MVC框架
5 springcloud 2024.0.1 微服务框架
6 springcloud Alibaba 2023.0.3.2 阿里巴巴微服务框架扩展

组件版本控制

序号 名称 版本 用途 备注
1 Nacos 2.5.1 服务注册发现、分布配置中⼼
2 Sentinel 1.8.8 服务限流降级 面向云原生微服务的高可用流控防护组件
3 Seata 2.3.0 分布式事务保证数据一致性

什么是⽹关

  • API Gateway,是系统的唯⼀对外的⼊⼝,介于客户端和服务器端之间的中间层,处理⾮业务功能 提供路由请求、鉴权、监控、缓存、限流等功能
  • 统⼀接⼊
    智能路由
    AB测试、灰度测试
    负载均衡、容灾处理
    ⽇志埋点(类似Nignx⽇志)
  • 流量监控
    限流处理
    服务降级
  • 安全防护
    鉴权处理
    监控
    机器⽹络隔离

主流的⽹关

  • zuul:是Netflix开源的微服务⽹关,和
    Eureka,Ribbon,Hystrix等组件配合使⽤,依赖组件⽐
    较多,性能教差
  • kong: 由Mashape公司开源的,基于Nginx的API
    gateway
  • nginx+lua:是⼀个⾼性能的HTTP和反向代理服务器,lua
    是脚本语⾔,让Nginx执⾏Lua脚本,并且⾼并发、⾮阻塞
    的处理各种请求
  • springcloud gateway: Spring公司专⻔开发的⽹关,替代
    zuul
    注意:AlibabaCloud对应的⽹关,⽤
    SpringCloud官⽅推荐的Gateway

什么是 SpringCloud Gateway

Spring官⽅出品,基于Spring5+Reactor技术开发的⽹关
性能强劲基于Reactor+WebFlux、功能多样基于springboot2.x, 直接可以jar包⽅式运⾏

官⽅⽂档
https://spring.io/projects/spring-cloud-gateway

项目使用

注:这里仅helloworld一下,下一小章节会按实际使用结合nginx使用。

新建微服务online-edu-gateway

image.png

image.png

建好之后删掉Main.java
image.png

配置online-edu-api-gateway/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>org.online_edu</groupId>
        <artifactId>online-edu</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>online-edu-api-gateway</artifactId>

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

</project>

新增并配置online-edu-api-gateway/src/main/java/org/online_edu/GatewayApplication.java

package org.online_edu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

}

新增并配置online-edu-api-gateway/src/main/resources/application.yml.

server:
  port: 8888

spring:
  application:
    name: online-edu-api-gateway
  cloud:
    gateway:
      routes: #数组形式
        - id: order-service #路由唯⼀标识
          uri: http://127.0.0.1:8000 #想要转发到的地址
          order: 1 #优先级,数字越⼩优先级越⾼
          predicates: #断⾔ 配置哪个路径才转发
            - Path=/order-server/**
          filters: #过滤器,请求在传递过程中通过过滤器修改
            - StripPrefix=1 #去掉第⼀层前缀
            #访问路径 http://localhost:8888/order-server/api/v1/video_order/list
            #转发路径 http://localhost:8000/order-server/api/v1/video_order/list
            #需要过滤器去掉前⾯第⼀层

启动网关服务online-edu-api-gateway和订单服务online-edu-order-service.

浏览器打开http://localhost:8888/order-server/api/v1/video_order/list

image.png

gateway整合nacos

  • 原先存在的问题
    微服务地址写死
    负载均衡没做到

实际使用中,我们不可能将微服务的地址和ip写死,而是通过nacos作为注册中心,进行自动的服务发现。

配置online-edu-api-gateway/pom.xml,增加naocs依赖。

<?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.online_edu</groupId>
        <artifactId>online-edu</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>online-edu-api-gateway</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--添加nacos客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- Spring Cloud 2020 版本后默认移除了 Ribbon,需手动添加 spring-cloud-loadbalancer 依赖以实现 lb:// 负载均衡路由。-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>
    </dependencies>

</project>

配置online-edu-api-gateway/src/main/resources/application.yml,增加nacos配置。

server:
  port: 8888

spring:
  application:
    name: online-edu-api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: xxx.xxx.xxx.xxx:8848
        username: nacos
        password: password
    gateway:
      routes: #数组形式
        - id: order-service #路由唯⼀标识
#          uri: http://127.0.0.1:8000 #想要转发到的地址
          uri: lb://online-edu-order-service # 从nacos获取名称转发,lb是负载均衡轮训策略
          order: 1 #优先级,数字越⼩优先级越⾼
          predicates: #断⾔ 配置哪个路径才转发
            - Path=/order-server/**
          filters: #过滤器,请求在传递过程中通过过滤器修改
            - StripPrefix=1 #去掉第⼀层前缀
            #访问路径 http://localhost:8888/order-server/api/v1/video_order/list
            #转发路径 http://localhost:8000/order-server/api/v1/video_order/list
            #需要过滤器去掉前⾯第⼀层
      discovery:
        locator:
          enabled: true #开启⽹关拉取nacos的服务

订单服务online-edu-order-service开启多实例启动。

image.png

image.png

修改端口再启动一个:
image.png

浏览器打开http://localhost:8888/order-server/api/v1/video_order/list
image.png

再次刷新


image.png

Gateway⽹关的配置项

以下仅作为网关功能演示。实际使用网关过程中,注意:

⽹关不要加太多业务逻辑,否则会影响性能,务必记住



image.png

路由:是⽹关的基本单元,由ID、URI、⼀组
Predicate、⼀组Filter组成,根据Predicate进⾏匹配转发

route组成部分

id:路由的ID
uri:匹配路由的转发地址
predicates:配置该路由的断⾔,通过PredicateDefinition类进⾏接收配置。
order:路由的优先级,数字越⼩,优先级越⾼

交互流程

  • 客户端向Spring Cloud Gateway发出请求
  • 如果⽹关处理程序映射确定请求与路由匹配
  • 则将其发送到⽹关Web处理程序
  • 通过特定过滤器链运⾏,前置处理-后置处理
image.png

Gateway内置的路由断⾔

什么是Gateway路由断⾔

  • Predicate 来源于Java8,接受输⼊参数,返回⼀个布尔值结果
  • Spring Cloud Gateway 中 Spring 利⽤ Predicate 的特性实现了各种路由匹配规则
  • 转发的判断条件,SpringCloud Gateway⽀持多种⽅式,常⻅如:Path、Query、Method、Header等
  • ⽀持多个Predicate请求的转发是必须满⾜所有的Predicate后才可以进⾏路由转发

内置路由断⾔—— RoutePredicateFactory 接⼝实现类

进入idea项目中,ctrl+N,搜索RoutePredicateFactory 类。


image.png

按住ctrl+Alt,点击接⼝实现类RoutePredicateFactory 名称,可以查询到下游的实现类:


image.png

参数编写规则 XXXRoutePredicateFactory,使⽤XXX作为
参数配置, 例如下⾯

predicates:
 - Host=
 - Path=
 - Method=
 - Header=
 - Query=
 - Cookie=

断言使用举例

比如,某个接口,要求在指定时间定时下线。过后不可以在被访问。

使⽤Before ,只要当前时间⼩于设定时间,路由才会匹配请求
东8区的2025-03-28T01:01:01.000+08:00后,请求不可访问

配置online-edu-api-gateway/src/main/resources/application.yml

server:
  port: 8888

spring:
  application:
    name: online-edu-api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: xxx.xxx.xxx.xxx:8848
        username: nacos
        password: password
    gateway:
      routes: #数组形式
        - id: order-service #路由唯⼀标识
#          uri: http://127.0.0.1:8000 #想要转发到的地址
          uri: lb://online-edu-order-service # 从nacos获取名称转发,lb是负载均衡轮训策略
          order: 1 #优先级,数字越⼩优先级越⾼
          predicates: #断⾔ 配置哪个路径才转发
            - Path=/order-server/**
            - Before=2025-03-28T01:01:01.000+08:00
#            - RewritePath=/order-server/(?<remaining>.*), /$\{remaining}
          filters: #过滤器,请求在传递过程中通过过滤器修改
            - StripPrefix=1 #去掉第⼀层前缀

      discovery:
        locator:
          enabled: true  #开启网关拉取nacos的服务

重新运行网关服务,浏览器运行,没问题(运行时,当前北京时间2025年3月27日)


image.png

改为Before=2025-03-26T01:01:01.000+08:00

浏览器运行:


image.png

例如增加必须传的参数

          predicates: #断⾔ 配置哪个路径才转发
            - Path=/order-server/**
            - Before=2025-03-28T01:01:01.000+08:00
            - Query=token

浏览器运行:

image.png
image.png

Gateway⽹关的过滤器

过滤器⽣命周期

  • PRE: 这种过滤器在请求被路由之前调⽤,⼀般⽤于鉴权、限流等
  • POST:这种过滤器在路由到微服务以后执⾏,⼀般⽤于修改响应结果,⽐如增加header信息、打点结果⽇志

⽹关过滤器分类

  • 局部过滤器GatewayFilter:应⽤在某个路由上,每个过滤器⼯⼚都对应⼀个实现类,并且这些类的名称必须以GatewayFilterFactory 结尾.内置很多全局过滤器,顶级接⼝ GlobalFilter
  • 全局过滤器:作⽤全部路由上,内置很多局部过滤器,顶级接⼝ GatewayFilterFactory

⾃定义全局过滤器实现鉴权

自定义实现,本质上就是模仿官方的过滤器,写一个自己的java类。
新建online-edu-api-gateway/src/main/java/org/online_edu/filter/UserGlobalFilter.java

package org.online_edu.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class UserGlobalFilter implements GlobalFilter, Ordered {
    /**
     * 处理Web请求并(可选地)委托给下一个{@code GatewayFilter}
     * 通过给定的{@link GatewayFilterChain}。
     *
     * @param chain 链提供了一种委托给下一个过滤器的方式
     * @param exchange 交换当前服务器交换
     * @return {@code Mono<Void>} 表示请求处理完成
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 写业务逻辑

        return null;
    }

    /**
     * 获取该对象的顺序值。
     * 值越高优先级越低。因此,
     * 具有最低值的对象具有最高优先级(在某种程度上)
     * 类似于Servlet {@code load-on-startup}值)。
     * 相同的顺序值将导致任意的排序位置受影响的对象。
     *
     * @return 返回排序阙值
     * @see #HIGHEST_PRECEDENCE
     * @see #LOWEST_PRECEDENCE
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

模拟写登录鉴权逻辑,这里引入一个工具包apache-commons-lang3

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.17.0</version>
</dependency>

如果拉不下来就手动下载一下。

DremoteRepositories=https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -DgroupId=org.apache.commons -DartifactId=commons-lang3 -Dversion=3.17.0
image.png
   @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 写业务逻辑
        String token = exchange.getRequest().getHeaders().getFirst("token");

        //TODO 根据业务开发对应的鉴权规则,比如JWT
        if (StringUtils.isBlank(token)) {
            // 返回401
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        //继续往下执⾏
        return chain.filter(exchange);
    }

online-edu-api-gateway/src/main/resources/application.yml记得注释掉多余的断言。

server:
  port: 8888

spring:
  application:
    name: online-edu-api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: xxx.xxx.xxx.xxx:8848
        username: nacos
        password: password
    gateway:
      routes: #数组形式
        - id: order-service #路由唯⼀标识
#          uri: http://127.0.0.1:8000 #想要转发到的地址
          uri: lb://online-edu-order-service # 从nacos获取名称转发,lb是负载均衡轮训策略
          order: 1 #优先级,数字越⼩优先级越⾼
          predicates: #断⾔ 配置哪个路径才转发
            - Path=/order-server/**
#            - Before=2025-03-28T01:01:01.000+08:00
#            - Query=token
          filters: #过滤器,请求在传递过程中通过过滤器修改
            - StripPrefix=1 #去掉第⼀层前缀

      discovery:
        locator:
          enabled: true  #开启网关拉取nacos的服务

运行:


image.png

配置请求,并发送:


image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容