GateWay使用手册

news2025/1/16 2:57:08

好的,下面是优化后的版本。为了提高可读性和规范性,我对内容进行了结构化、简化了部分代码,同时增加了注释说明,便于理解。


1. 引入依赖

pom.xml 中添加以下依赖:

<dependencies>
    <!-- Spring Cloud Gateway:提供API网关功能 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

    <!-- Spring Cloud Alibaba Nacos Discovery:用于服务发现 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

    <!-- Spring Cloud Loadbalancer:提供客户端负载均衡 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>
</dependencies>

2. 启动类 (GateApplication.java)

定义主启动类,启动 Spring Boot 应用:

@SpringBootApplication  // 标明这是Spring Boot应用的入口
public class GateApplication {
    public static void main(String[] args) {
        SpringApplication.run(GateApplication.class, args);  // 启动应用
    }
}

3. 配置文件 (application.yml)

配置网关的基本设置、Nacos 服务发现以及路由规则。

server:
  port: 8080  # 配置网关监听的端口

spring:
  application:
    name: gateway  # 应用名称,用于 Nacos 等服务发现

  cloud:
    nacos:
      discovery:
        server-addr: xiaotianlong.xyz:8848  # 配置 Nacos 服务器地址

    gateway:
      routes:  # 配置网关的路由规则
        # 路由规则 1
        - id: service_name  # 路由的唯一ID
          uri: lb://service_name  # 使用负载均衡访问注册到 Nacos 中的服务
          predicates:
            - Path=/user/**  # 请求路径以 `/user/` 开头时触发此路由
          filters:
            - AddRequestHeader=X-Request-Foo, Bar  # 添加请求头

        # 路由规则 2
        - id: service_name2
          uri: lb://service_name2
          predicates:
            - Path=/order/**  # 请求路径以 `/order/` 开头时触发此路由

4. 自定义全局过滤器

定义一个全局过滤器,记录请求的时间并打印日志。

@Component  // 声明为Spring组件
public class MyGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 记录请求开始时间
        System.out.println("请求开始时间: " + System.currentTimeMillis());
        
        // 放行请求
        return chain.filter(exchange)
                .then(Mono.fromRunnable(() -> {
                    // 记录请求结束时间
                    System.out.println("请求结束时间: " + System.currentTimeMillis());
                }));
    }

    @Override
    public int getOrder() {
        // 过滤器的执行顺序,数字越小优先级越高
        return 0;
    }
}

5. 自定义Gateway过滤器

创建一个自定义的 Gateway 过滤器工厂,允许动态配置过滤器的参数。

@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {

    // 内部配置类,允许用户配置过滤器的参数
    @Data
    public static class Config {
        private String pattern = "yyyy-MM-dd";  // 设置默认日期格式
        private String message = "默认日志信息";  // 自定义日志信息
    }

    public MyGatewayFilterFactory() {
        super(Config.class);  // 指定配置类类型
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return List.of("pattern", "message");  // 设置快捷字段顺序
    }

    @Override
    public GatewayFilter apply(Config config) {
        // 创建过滤器逻辑
        return new OrderedGatewayFilter((exchange, chain) -> {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(config.getPattern());
            System.out.println("请求开始时间: " + formatter.format(LocalDateTime.now()));
            System.out.println(config.getMessage());  // 打印自定义日志信息
            return chain.filter(exchange)
                    .then(Mono.fromRunnable(() -> {
                        System.out.println("请求结束时间: " + formatter.format(LocalDateTime.now()));
                    }));
        }, 1);//在这里设置顺序
    }
}

6. 配置自定义过滤器

application.yml 文件中配置自定义的 MyGatewayFilterFactory 过滤器,使其生效:

spring:
  cloud:
    gateway:
      routes:
        - id: example_route
          uri: lb://some-service
          predicates:
            - Path=/somepath/**  # 路径匹配条件
          filters:
            - name: My  # 使用自定义过滤器
              args:
                pattern: "yyyy-MM-dd~HH:mm:ss"  # 自定义日期格式
                message: "这是一个统计时间的gateway过滤器"  # 自定义日志信息

或者

spring:
  cloud:
    gateway:
      routes:
        - id: example_route
          uri: lb://some-service
          predicates:
            - Path=/somepath/**  # 路径匹配条件
          filters:
             # 由于设置了shortcutfieldorder,所以可以这样写
            - My="yyyy-MM-dd~HH:mm:ss", "这是一个统计时间的gateway过滤器"

案例1:登录检验

@Component
@EnableConfigurationProperties(AuthProperties.class)
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    @Resource
    private AuthProperties authProperties;
    @Resource
    private JwtTool jwtTool;

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取request
        ServerHttpRequest request = exchange.getRequest();
        //2.判断路径是否需做登录拦截
        List<String> excludePaths = authProperties.getExcludePaths();
        if (isExclude(request.getPath())) {
            //此时不需要拦截,直接放行
            return chain.filter(exchange);
        }
        //3.获得token
        String token = request.getHeaders().getFirst("authorization");
        //4.检验并解析token
        Long userId = null;
        try {
            userId = jwtTool.parseToken(token);
        } catch (Exception e) {
            //设置响应状态码为401
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            //拦截
            return response.setComplete();
        }
        //todo 5.传递用户信息

        //6.放行
        return chain.filter(exchange);
    }

    private boolean isExclude(RequestPath path) {
        List<String> excludePaths = authProperties.getExcludePaths();
        for (String pattern : excludePaths) {
            if (antPathMatcher.match(pattern, path.toString())) {
                return true;
            }
        }
        return false;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

7.结合Nacos实现动态路由

在Spring Cloud Gateway中,路由的配置默认是在项目启动时通过 org.springframework.cloud.gateway.route.CompositeRouteDefinitionLocator 进行加载的。这些配置一旦加载到内存中(通常是通过一个 Map 缓存),就不会随路由变化而更新,也不支持热更新功能。因此,我们需要借助 Nacos 来实现动态的路由更新功能。

这涉及到两个关键问题:

  • 如何监听Nacos配置变更?
  • 如何把新的路由信息更新到路由表中?

7.1 引入依赖

首先,我们需要在项目中引入Nacos的配置和启动依赖:

<!-- 统一配置管理 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

<!-- 加载bootstrap配置 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

7.2 配置bootstrap.yaml

在网关项目的 resources 目录下,创建 bootstrap.yaml 文件,配置Nacos的服务地址和路由配置的相关信息:

spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: xiaotianlong.xyz:8848
      config:
        server-addr: xiaotianlong.xyz:8848

7.3 定义配置监听器

接下来,我们编写一个配置监听器类,用于监听Nacos配置变更并更新路由。监听器需要通过 NacosConfigManager 获取配置内容,并在路由配置更新时,动态更新路由表。

package com.hmall.gateway.route;

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.hmall.common.utils.CollUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {

    private final RouteDefinitionWriter writer;
    private final NacosConfigManager nacosConfigManager;

    // 路由配置文件的dataId和group
    private final String dataId = "gateway-routes.json";
    private final String group = "DEFAULT_GROUP";
    // 保存已更新的路由ID
    private final Set<String> routeIds = new HashSet<>();

    @PostConstruct
    public void initRouteConfigListener() throws NacosException {
        // 注册Nacos配置监听器并拉取配置
        String configInfo = nacosConfigManager.getConfigService()
                .getConfigAndSignListener(dataId, group, 5000, new Listener() {
                    @Override
                    public Executor getExecutor() {
                        return null;  // 默认执行器为null
                    }

                    @Override
                    public void receiveConfigInfo(String configInfo) {
                        updateConfigInfo(configInfo);  // 配置变更时更新路由
                    }
                });
        // 首次启动时加载配置
        updateConfigInfo(configInfo);
    }

    private void updateConfigInfo(String configInfo) {
        log.debug("监听到路由配置变更:{}", configInfo);
        // 1. 反序列化配置
        List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class);
        
        // 2. 清除旧路由配置
        routeIds.forEach(routeId -> writer.delete(Mono.just(routeId)).subscribe());
        routeIds.clear();
        
        // 3. 判断并更新新的路由配置
        if (CollUtils.isEmpty(routeDefinitions)) {
            // 如果没有新的路由配置,直接结束
            return;
        }
        
        // 4. 更新新的路由配置
        routeDefinitions.forEach(routeDefinition -> {
            // 保存新路由
            writer.save(Mono.just(routeDefinition)).subscribe();
            // 记录路由ID,方便未来删除
            routeIds.add(routeDefinition.getId());
        });
    }
}

在Nacos控制台,我们可以添加路由配置文件 gateway-routes.json,类型选择JSON。路由配置的示例内容如下:
在这里插入图片描述

[
    {
        "id": "item",
        "predicates": [{
            "name": "Path",
            "args": {"_genkey_0":"/items/**", "_genkey_1":"/search/**"}
        }],
        "filters": [],
        "uri": "lb://item-service"
    },
    {
        "id": "cart",
        "predicates": [{
            "name": "Path",
            "args": {"_genkey_0":"/carts/**"}
        }],
        "filters": [],
        "uri": "lb://cart-service"
    },
    {
        "id": "user",
        "predicates": [{
            "name": "Path",
            "args": {"_genkey_0":"/users/**", "_genkey_1":"/addresses/**"}
        }],
        "filters": [],
        "uri": "lb://user-service"
    },
    {
        "id": "trade",
        "predicates": [{
            "name": "Path",
            "args": {"_genkey_0":"/orders/**"}
        }],
        "filters": [],
        "uri": "lb://trade-service"
    },
    {
        "id": "pay",
        "predicates": [{
            "name": "Path",
            "args": {"_genkey_0":"/pay-orders/**"}
        }],
        "filters": [],
        "uri": "lb://pay-service"
    }
]

通过以上配置,网关将能够动态地加载和更新路由配置,使得路由在Nacos配置变更时自动同步更新。

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

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

相关文章

在内网工作时,如何使用 vscode remote ssh 去连接内网服务器?

来源&#xff1a;https://stackoverflow.com/questions/56671520/how-can-i-install-vscode-server-in-linux-offline 看这个回答&#xff1a; 一般来说&#xff0c;内网会提供 vscode 安装包&#xff0c;remote-ssh 的 vsix&#xff0c;先安装好。 随后&#xff0c;保证自己…

学习日记_20241126_聚类方法(自组织映射Self-Organizing Maps, SOM)

前言 提醒&#xff1a; 文章内容为方便作者自己后日复习与查阅而进行的书写与发布&#xff0c;其中引用内容都会使用链接表明出处&#xff08;如有侵权问题&#xff0c;请及时联系&#xff09;。 其中内容多为一次书写&#xff0c;缺少检查与订正&#xff0c;如有问题或其他拓展…

吉客云数据集成技巧:智能实现MySQL物料信息查询

吉客云数据集成技巧&#xff1a;智能实现MySQL物料信息查询 吉客云数据集成到MySQL&#xff1a;物料信息查询案例分享 在企业的数据管理和分析过程中&#xff0c;数据的高效集成与处理至关重要。本文将聚焦于一个具体的系统对接集成案例——吉客云物料信息查询到BI拉伯塔的物料…

Flink cdc同步增量数据timestamp字段相差八小时(分析|解决)不是粘贴复制的!

问题 我使用flink cdc同步mysql到mysql遇到了timestamp字段缺少八小时的问题。很少无语&#xff0c;flink ,cdc,debezium时区都设置了&#xff0c;没有任何效果&#xff01; 分析 问题出现在mysql binlog身上&#xff01;&#xff01;&#xff01; 因为默认mysql会使用UTC来…

QUICK 调试camera-xml解析

本文主要介绍如何在QUICK QCS6490使能相机模组。QCS6490的相机基于CameraX的框架&#xff0c;只需通过配置XML文件&#xff0c;设置相机模组的相关参数&#xff0c;就可以点亮相机。本文主要介绍Camera Sensor Module XML和Camera Sensor XML配置的解析&#xff0c;这中间需要c…

ArcGIS 软件中路网数据的制作

内容导读 路网数据是进行网络分析的基础&#xff0c;它是建立网络数据集的数据来源。 本文我们以OSM路网数据为例&#xff0c;详细介绍OSM路网数据从下载&#xff0c;到数据处理&#xff0c;添加属性&#xff0c;完成符合网络分析的网络数据集的全部过程。 01 数据获取 比较…

Flink双流Join

在离线 Hive 中&#xff0c;我们经常会使用 Join 进行多表关联。那么在实时中我们应该如何实现两条流的 Join 呢&#xff1f;Flink DataStream API 为我们提供了3个算子来实现双流 join&#xff0c;分别是&#xff1a; join coGroup intervalJoin 下面我们分别详细看一下这…

【Python-Open3D学习笔记】005Mesh相关方法

TriangleMesh相关方法 文章目录 TriangleMesh相关方法1. 查看mesh三角形面信息2. 可视化三角形3. 上采样4. 计算mesh形成的面积和体积 1. 查看mesh三角形面信息 def view_hull_triangles(hull: o3d.geometry.TriangleMesh):"""查看mesh三角形面信息&#xff08…

【LeetCode热题100】优先级队列

这盘博客记录了关于优先级队列的几道题&#xff0c;包括最后一块石头的重量、数据流中的第K大元素、前K个高频单词、数据流的中位数。 class Solution { public:int lastStoneWeight(vector<int>& stones) {priority_queue<int> heap;for(auto s : stones) hea…

node.js基础学习-cheerio模块-简单小爬虫(五)

学习cheerio模块&#xff0c;简单做一个爬取图片网站的图片&#xff0c;并且将这些图片下载到本地指定的文件夹下&#xff0c;很多图片网站都有一些反爬取的机制&#xff0c;找的好几个都会报302错误&#xff0c;所以我找了一个小的图片网站&#xff0c;这个没有反爬取机制&…

技术创新与人才培养并重 软通动力子公司鸿湖万联亮相OpenHarmony人才生态大会

11月27日&#xff0c;由开放原子开源基金会指导&#xff0c;OpenHarmony项目群工作委员会主办的OpenHarmony人才生态大会2024在武汉隆重举办。软通动力子公司鸿湖万联作为OpenHarmony项目群A类捐赠人应邀出席。大会期间&#xff0c;鸿湖万联不仅深度参与了OpenHarmony人才生态年…

FFmpeg 推流给 FreeSWITCH

FFmpeg 推流&#xff0c;貌似不难&#xff0c;网上有很多资料, 接到一个任务&#xff0c;推流给 FreeSWITCH&#xff0c;最开始以为很容易&#xff0c; 实则不然&#xff0c;FreeSWITCH uuid_debug_media <uuid>&#xff0c; 一直没人任何反应 仔细一查&#xff0c;Fr…

彻底理解quadtree四叉树、Octree八叉树 —— 点云的空间划分的标准做法

1.参考文章&#xff1a; &#xff08;1&#xff09;https://www.zhihu.com/question/25111128 这里面的第一个回答&#xff0c;有一幅图&#xff1a; 只要理解的四叉树的构建&#xff0c;对于八叉树的构建原理类比方法完全一样&#xff1a;对于二维平面内的随机分布的这些点&…

【工具变量】上市公司企业数字化转型指数(甄红线版本,战略引领、技术驱动、环境支撑、数字化成果及应用)2011-2022年

一、测算方式&#xff1a;参考《经济研究》甄红线&#xff08;2023&#xff09;老师研究的做法&#xff0c;本文采用 &#xff23;&#xff33;&#xff2d;&#xff21;&#xff32; 数据库中国上市公司数字化转型研究数据库中企业数字化转型指数来衡量企业数字化转型水平。 数…

长短期记忆网络 (LSTM) 简介

文章目录 一、说明二、传统 RNN 的问题三、为什么梯度消失&#xff1f;四、长短期记忆网络简介五、忘记门六、Update Gate (Input Gate)七、Output Gate八、数学上的内存九、从 LSTM 到 Transformer十、总结 一、说明 机器学习取得进步的领域之一是自然语言处理。对于用于机器…

安卓悬浮窗应用外无法穿透事件问题

现象&#xff1a; 应用内悬浮窗如何设置了 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE在自己应用内事件穿透正常&#xff0c;但到应用外就无法点击。 原因&#xff1a; 解决方法&#xff1a; layoutParams.alpha 0.8f …

linux minio安装

安装minio&#xff08;Centos&#xff09; 1. 查看服务器版本uname -a 2. 到minio官网下载对应的版本 官网地址&#xff1a;minio官网下载 根据上面查看的信息是x86_64系统所以我们下载linu-amd64 3. 上传到服务器 新建minioServer目录 上传至该目录下 赋权 chmod x mi…

JavaScript字符串

这张图片主要介绍了JavaScript中的字符串类型&#xff08;string&#xff09;。 字符串 1. 字符串的定义 在JavaScript中&#xff0c;通过单引号&#xff08;&#xff09;、双引号&#xff08;"&#xff09;或反引号&#xff08;&#xff09;包裹的数据都叫字符串。单引…

Linq中的投影运算 (C#):Select、SelectMany、Zip

投影是指将对象转换为一种新形式的操作&#xff0c;该形式通常只包含那些将随后使用的属性。 通过使用投影&#xff0c;您可以构造从每个对象生成的新类型。 可以投影属性&#xff0c;并对该属性执行数学函数。 还可以在不更改原始对象的情况下投影该对象。 1、Select 下面的…

RabbitMQ在手动消费的模式下设置失败重新投递策略

最近在写RabbitMQ的消费者&#xff0c;因为业务需求&#xff0c;希望失败后重试一定次数&#xff0c;超过之后就不处理了&#xff0c;或者放入死信队列。我这里就达到重试次数后就不处理了。本来以为很简单的&#xff0c;问了kimi&#xff0c;按它的方法配置之后&#xff0c;发…