Spring Cloud Gateway 网关的使用

news2025/7/13 22:44:14

在之前的学习中,所有的微服务接口都是对外开放的,这就意味着用户可以直接访问,为了保证对外服务的安全性,服务端实现的微服务接口都带有一定的权限校验机制,但是由于使用了微服务,就需要每一个服务都进行一个校验,当校验逻辑需要修改时,又得修改多个应用,增加了开发负担,一个解决方式就是引入 API 网关,类似整个微服务架构的门面,所有的外部客户端都需要经过它来进行调度和过滤,相当于前台,需要办理什么业务,经过前台的确认之后会引导用户去对应的服务台

作为网关,具有以下的几个核心功能:

  1. 权限控制:对用户进行权限校验,如果校验失败就进行拦截
  2. 动态路由:一切请求先经过网关,但网关不处理业务,而是根据某种规则,把请求发送到某个微服务
  3. 负载均衡:当路由的目标服务有多个时,进行负载均衡
  4. 限流:当请求流量过高时,按照网关中配置微服务能够接受的流量进行放行,避免服务压力过大

Gateway

1. Gateway 的使用

首先需要创建一个单独的 Gateway 的服务,除了引入 gateway 的依赖之外,还需要引入 nacos 和 loadbalancer 的依赖

<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>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  </dependency>
</dependencies>

然后就需要对网关进行配置:

spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:  #网关路由配置
        - id: order-service #自定义路由规则id
          uri: lb://order-service/  #目标服务地址
          predicates:  #路由条件(满足条件才会被通行)
            - Path=/order/**

来解释一下上面的配置:

由于需要用到 Nacos 的服务发现功能,所以要把 Nacos 的配置也添加上,之后就是网关的路由配置,自定义一个路由规则 id 作为唯一标识符,方便后续对该规则进行管理和引用,然后就是目标服务地址, lb 表示使用负载均衡器将请求转发到名为 order-service 的服务,并设置了路由条件,请求的路径必须以 /order/ 开头

配置好之后启动服务,此时就可以通过网关服务来获取资源了

关于多个服务和多个路由条件的配置:

routes:  #网关路由配置
  - id: order-service #自定义路由规则id
    uri: lb://order-service/  #目标服务地址
    predicates:  #路由条件(满足条件才会被通行)
      - Path=/order/**,/feign/**
  - id: product-service
    uri: lb://product-service
    predicates:
      - Path=/product/**

2. Route Predicate Factories

在上面的配置中,使用 predicates 来配置路由条件,其中写的规则只是字符串形式,这些字符串会被 Route Predicate Factory (路由断言工厂,也称为路由谓词工厂)读取并处理,转变为路由判断条件

https://docs.spring.io/spring-cloud-gateway/reference/spring-cloudgateway/request-predicates-factories.html

也就是这 12 种基本的实现:

来演示一下 After 的使用,如果不符合条件就会不能够访问

predicates:  #路由条件(满足条件才会被通行)
  - Path=/order/**,/feign/**
  - After=2026-01-12T18:10:21.024727900+08:00[Asia/Shanghai]

3. Gateway Filter Factories

Predicate 是决定了请求由哪一个路由处理,Filter 过滤器是在请求处理前后做一些的逻辑的处理

Filter 又分为 Pre 和 Post 两种类型:

Pre 类型过滤器:路由处理之前执行,也就是请求转发给后端服务之前,例如对请求进行限流,添加额外的请求头信息等

Post 类型过滤器:请求执行完成后,将结果返回给客户端之前执行,例如修改响应体的主体内容,对响应路径进行重写等

Spring Cloud Gateway 中内置了很多的过滤器,用于拦截和处理 web 请求,根据作用范围可以分为 GatewayFilter (作用到单个路由或者一个分组的路由上),GlobalFilter(作用到所有的路由上)

来演示一下 AddRequestParameter 用法:

接下来再访问接口,即使 id 不传值也通过过滤器处理之后就被赋值了

除了 AddRequestParameter,观望中还提供了很多其它的过滤器

AddRequestHeader GatewayFilter Factory :: Spring Cloud Gateway

RequestRateLimiter 可以对通过网关的请求进行限流操作,采用的是令牌桶的算法

关于限流的算法有以下几种:

  1. 固定窗口:将时间划分为固定大小的窗口,每个窗口有一个计数器,用于记录在该窗口内允许通过的请求数量,每通过一个请求计数器就加一,当计数器达到设定的阈值就不允许请求通过,缺点也是非常明显,比如设定 10 分钟可以通过 10000 个请求,前 9 分钟都没有请求,最后 1 分钟处理 10000 个请求也符合要求,显然是不合理的
  2. 滑动窗口:同样将时间划分为多个小的时间窗口,但不是按固定的大窗口重置计数器,而是将窗口滑动,这也就解决了固定窗口出现的问题,不过需要记录多个小窗口的信息,性能开销比较大
  3. 漏桶算法:就像一个漏斗型的水桶,当请求到达时,会先进入漏桶,如果漏桶未满,则允许请求通过;如果漏桶已满,则拒绝请求,桶以恒定的速率出水,代表处理请求的速率,无论流入的速率如何,流出的速率始终保持一致,这也就导致了不能够处理突发的大流量
  4. 令牌桶算法:在漏桶的基础上,令牌桶中会以一定的速率生成令牌,当流量小的时候,桶中就会不断积累令牌,当遇到突发的大流量,就可以直接拿着这些令牌通过,剩余的就排队等待令牌的生成,排队等待这种处理方式,还可以结合其他策略,比如当排队队列过长时,为了避免资源过度占用,可能会对部分请求进行拒绝;或者根据业务的优先级,优先处理高优先级请求等。

再来看下一个过滤器:

Retry 就是根据当前返回的状态码来进行重试,可以设置状态码和重试次数

在上面的配置中都是使用 filter 进行配置的,如果使用 Default Filters 配置的话就是对全部路由生效

来使用 default-filters 配置一下 retry,然后把状态码设置为 502

之后就重新请求了 3 次

GlobalFilter 是全局过滤器,会应用到所有的路由请求上,全局过滤器通常用于实现安全性,性能监控和日志记录等相关的全局功能

关于负载均衡,在之前的使用中就已经用到了,也就是 GlobalFilter

下面看一下 Metrics 怎么使用,首先需要引入下面的依赖

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

然后再开启 metrics 的配置

然后再添加一下配置,用来监控详细的信息,在 /actuator 下可以查到所有监控的链接和信息

过滤器的执行顺序:

当一个项目中,既有 GatewayFilter 又有 GlobalFilter 时,请求路由后,网关会把当前项目中的 GatewayFilter 和 GlobalFilter 合并到一个 过滤器链中,并进行排序,依次执行过滤器

每一个过滤器都必须指定一个 int 类型的 order 值,默认值为 0 ,来表示过滤器的优先级,order 值越小,优先级越高,执行顺序越靠前

Filter 通过实现 Order 接口或者添加@Order注解来指定 order 值,Spring Cloud Gateway 提供的 Filter 由 Spring 指定,用户也可以自定义 Filter,如果过滤器的 order 值一样,会按照 defaultFilter > GatewayFilter > GlobalFilter 的顺序执行

4. 自定义过滤器

4.1. 自定义 GlobalFilter

全局过滤器需要实现 GlobalFilter,Ordered 接口,然后重写 filter 和 getOrder 方法

@Slf4j
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //Pre执行逻辑
        log.info("Pre Global Filter...");
        return chain.filter(exchange).then(Mono.fromRunnable(()->{
            //Post执行逻辑
            log.info("Post Global Filter...");
        }));
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE; //设置优先级
    }
}

关于 Mono 方法参数的说明:

之后再去发起请求,自定义的全局过滤器已经生效了

4.2. 自定义 GatewayFilter

如果需要自定义可配置的 GatewayFilter,就需要创建一个过滤器工厂,根据读取到的配置来构造对象

定义一个类用来存储从配置文件中读取到的配置信息

@Data
public class CustomConfig {
    private String name;
}

创建一个过滤器工厂 CustomGatewayFilterFactory 继承 AbstractGatewayFilterFactory 类,然后再实现 Ordered 接口,并添加过滤器的逻辑

@Slf4j
@Component
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomConfig> implements Ordered {

    public CustomGatewayFilterFactory() {
        super(CustomConfig.class);
    }


    @Override
    public GatewayFilter apply(CustomConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                //Pre类型
                log.info("Pre Filter,config{}",config);
                return chain.filter(exchange).then(Mono.fromRunnable(()->{
                    log.info("Post Filter,config{}",config);
                }));
            }
        };
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}

配置文件中把自定义的过滤器名称添加上,然后还需要添加传入的参数,这里过滤器的名称取的是 CustomGatewayFilterFactory 除去 GatewayFilterFactory,按照规范自定义过滤器工厂需要以 GatewayFilterFactory 为后缀

之后再启动服务,自定义的 GatewayFilter 也生效了,并且在指定优先级相同的条件下,先执行 GatewayFilter 再执行 GlobalFilter

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2309596.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaWeb-jdk17安装

下载jdk17 地址&#xff1a;https://www.oracle.com/java/technologies/downloads/#jdk17-windows 安装jdk 配置环境变量 右键点击我的电脑>属性>高级系统设置>环境变量 在系统变量Path变量中添加 测试 java -version javac -version

【银河麒麟高级服务器操作系统】服务器测试业务耗时问题分析及处理全流程分享

更多银河麒麟操作系统产品及技术讨论&#xff0c;欢迎加入银河麒麟操作系统官方论坛 https://forum.kylinos.cn 了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer…

算法1-4 蜜蜂路线

题目描述 一只蜜蜂在下图所示的数字蜂房上爬动,已知它只能从标号小的蜂房爬到标号大的相邻蜂房,现在问你&#xff1a;蜜蜂从蜂房 m 开始爬到蜂房 n&#xff0c;m<n&#xff0c;有多少种爬行路线&#xff1f;&#xff08;备注&#xff1a;题面有误&#xff0c;右上角应为 n−…

Android 常见View的防抖

在开发Android应用时&#xff0c;我们经常会遇到用户快速点击按钮或者频繁触发某个事件的情况。这种行为可能会导致不必要的重复操作&#xff0c;例如多次提交表单、重复加载数据等。为了避免这些问题&#xff0c;我们需要对这些事件进行防抖处理。本文将详细介绍如何在Kotlin中…

数据库原理SQL查询(习题+知识点)

一、查询学生表所有学生记录 1.题目内容代码编写 select * from stu; 2.知识点提醒 1&#xff09;选择表中的所有属性列有两种方法 在select关键字后列出所有列名若列的显示顺序与其在表中的顺序相同&#xff0c;则也可用 * 表示所有列 二、查询学生表中部分信息 1.题目内…

安路FPGA开发入门:软件安装与点灯与仿真(TangDynasty ModelSim)

文章目录 前言软件安装开发软件仿真软件 点灯测试代码编写与编译引脚分配固件下载 仿真测试ModelSim添加仿真库TangDynasty仿真设置进行仿真 后记 前言 最近因为工作需要用安路的FPGA&#xff0c;这里对安路FPGA开发相关流程做个记录。作为测试只需要一个核心板&#xff08;我这…

浅克隆与深克隆区别

package d12_api_object;public class Test2 {public static void main(String[] args) throws CloneNotSupportedException {//目标&#xff1a;掌握Object类提供的对象克隆方法//1、protected Object clone():对象克隆User u1 new User(1,"min","1120",…

如何实现小数据的大智能?

大数据可以通过从态到势、从感到知的态势感知过程计算出可能性&#xff0c;如各种大模型&#xff0c;而要通过小数据、小样本获得好的预测结果&#xff0c;可以通过从势到态、从知到感的势态知感过程算计出可能性。 一般情况下&#xff0c;大家常常会提到了大数据和小数据在态势…

打开 Windows Docker Desktop 出现 Docker Engine Stopped 问题

一、关联文章: 1、Docker Desktop 安装使用教程 2、家庭版 Windows 安装 Docker 没有 Hyper-V 问题 3、安装 Windows Docker Desktop - WSL问题 二、问题解析 打开 Docker Desktop 出现问题,如下: Docker Engine Stopped : Docker引擎停止三、解决方法 1、检查服务是否…

基于单片机和蓝牙通讯的简易钢琴控制装置设计

摘要&#xff1a;本文设计了一个基于单片机和蓝牙通讯的简易钢琴演奏控制装置&#xff0c;在 Proteus 中设计绘制了系统电路原理图&#xff0c;在 Keil 中编写了单片机控制程序并导入 Proteus电路原理图中进行了软、硬件交互仿真&#xff0c;设置了手机蓝牙串口调试的键盘设置及…

React Native从入门到进阶详解

React Native知识框架从入门到进阶的问题。首先需要结合我搜索到的资料来整理出结构化的内容。证据中有多本书籍和文章&#xff0c;可能会涉及不同的章节和重点&#xff0c;需要仔细梳理。 首先&#xff0c;根据邱鹏源的《React Native精解与实战》将知识分为入门和进阶两大部分…

STL——list的介绍和模拟实现

前言 本篇博客我们将要开始介绍list这个容器&#xff0c;list是带头双向循环链表&#xff0c;STL标准模板库中实现了list这样方便我们去使用&#xff0c;那么本篇博客我们将脱下list的神秘外衣&#xff0c;介绍它的使用以及模拟实现。 list的介绍 list的底层是带头双向循环链…

go前后端开源项目go-admin,本地启动

https://github.com/go-admin-team/go-admin 教程 1.拉取项目 git clone https://github.com/go-admin-team/go-admin.git 2.更新整理依赖 go mod tidy会整理依赖&#xff0c;下载缺少的包&#xff0c;移除不用的&#xff0c;并更新go.sum。 # 更新整理依赖 go mod tidy 3.编…

go 分布式redis锁的实现方式

go 语言以高并发著称。那么在实际的项目中 经常会用到锁的情况。比如说秒杀抢购等等场景。下面主要介绍 redis 布式锁实现的两种高并发抢购场景。其实 高并发 和 分布式锁 是一个互斥的两个状态&#xff1a; 方式一 setNX&#xff1a; 使用 redis自带的API setNX 来实现。能解决…

深入理解递归:从原理到C++实践

什么是递归&#xff1f; 递归&#xff08;Recursion&#xff09;是编程中一种强大的技术&#xff0c;其核心思想是&#xff1a;函数直接或间接地调用自身。如同俄罗斯套娃一般&#xff0c;每个函数调用都会解开问题的一个层级&#xff0c;直到达到基础条件。 递归三要素&…

MyBatis-Plus 入门详解:从零搭建高效持久层

一、MyBatis-Plus 简介 MyBatis-Plus&#xff08;简称 MP&#xff09;是 MyBatis 的增强工具&#xff0c;在保留 MyBatis 原生功能的基础上&#xff0c;提供了全自动化的 CRUD 操作、强大的分页插件、代码生成器等功能&#xff0c;显著减少开发工作量。与原生 MyBatis 相比&…

阿里云物联网获取设备属性api接口:QueryDevicePropertyData

阿里云物联网接口&#xff1a;QueryDevicePropertyData 说明&#xff1a;调用该接口查询指定设备或数字孪生节点&#xff0c;在指定时间段内&#xff0c;单个属性的数据 比如提取上传到物联网的温度数据 api文档&#xff1a;QueryDevicePropertyData_物联网平台_API文档-阿里…

歌曲分类和流行度预测

1. 项目介绍 本项目从kaggle平台上下载了数据集&#xff0c;该数据集包含了3万多首来自Spotify API 的歌曲&#xff0c;共有23个特征。首先对数据集进行预处理&#xff0c;如重复行、缺失值、标准化处理等。再对预处理后的数据进行探索性分析&#xff0c;观察各变量的分布情况&…

不重启mysql情况下排查慢SQL

查状态 mysql> show variables like %slow_query_log%; 开启慢日志 mysql> set global slow_query_logON; 设置1s超时 mysql> set global long_query_time1; 如果想更小&#xff0c;可以设置0.5 查看慢SQL的日志 cat /var/lib/mysql/localhost-slow.log &…

27、Java 反射机制

15-1 Java 反射机制概述 Reflection&#xff08;反射&#xff09;是被视为动态语言的关键 动态语言&#xff1a;在运行时代码可以根据某些条件改变自身结构。如 C#\JavaScript\PHP 静态语言&#xff1a;运行时结构不可变的语言。如 Java\C\C 问题&#xff1a;通过直接new的方…