GateWay使用手册

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


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配置变更时自动同步更新。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Go 基础】channel

Go 基础 channel 什么是channel&#xff0c;为什么它可以做到线程安全 Go 的设计思想就是&#xff1a;不要通过共享内存来通信&#xff0c;而是通过通信来共享内存。 前者就是传统的加锁&#xff0c;后者就是 channel。也即&#xff0c;channel 的主要目的就是在多任务间传递…

C# 解决【托管调试助手 “ContextSwitchDeadlock“:……】问题

文章目录 一、遇到问题二、解决办法 一、遇到问题 托管调试助手 “ContextSwitchDeadlock”:“CLR 无法从 COM 上下文 0x56e81e70 转换为 COM 上下文 0x56e81d48&#xff0c;这种状态已持续 60 秒。拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows …

Spring AI 框架介绍

Spring AI是一个面向人工智能工程的应用框架。它的目标是将Spring生态系统的设计原则&#xff08;如可移植性和模块化设计&#xff09;应用于AI领域&#xff0c;并推广使用pojo作为AI领域应用的构建模块。 概述 Spring AI 现在(2024/12)已经支持语言&#xff0c;图像&#xf…

使用Grafana K6来测测你的系统负载能力

背景 近期我们有个号称会有很高很高并发的系统要上线&#xff0c;为了测试一下自己开发的系统的负载能力&#xff0c;准备了点海克斯科技&#xff0c;来看看抗不抗的住。 之前笔者写过用Apache JMeter进行压力测试的文章&#xff08;传送门&#x1f449;&#xff1a;https://…

32 从前序与中序遍历序列构造二叉树

32 从前序与中序遍历序列构造二叉树 32.1 从前序与中序遍历序列构造二叉树解决方案 class Solution { public:TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {return buildTreeHelper(preorder, inorder, 0, 0, inorder.size() - 1)…

【C++boost::asio网络编程】有关异步读写api的笔记

异步读写api 异步写操作async_write_someasync_send 异步读操作async_read_someasync_receive 定义一个Session类&#xff0c;主要是为了服务端专门为客户端服务创建的管理类 class Session { public:Session(std::shared_ptr<asio::ip::tcp::socket> socket);void Conn…

Flutter如何适配RTL

阿拉伯语和希伯来语等是使用的从右到左书写的文字系统。世界上估计有4.22亿人以阿拉伯语做为母语。使用从右至左的人口可以说是更多了。所以对于出海项目来说&#xff0c;是不能忽视的一部分。 RTL可以说是本地化适配中比较麻烦的一项&#xff0c;并没有多语言适配来的简单。RT…

【Django-xadmin】

时间长不用,会忘的系列 1、Django-xadmin后台字段显示处理 主要是修改每个模块下adminx.py文件 代码解释&#xff1a;第1行控制表单字段显示第2行控制列表字段显示第3行控制搜索条件第4行控制过滤条件第5行支持单个或多个字段信息修改第6行列表分页&#xff0c;每页显示多少行…

Pytest --capture 参数详解:如何控制测试执行过程中的输出行为

--capture 选项用于控制测试用例执行过程中标准输出&#xff08;stdout&#xff09;和标准错误输出&#xff08;stderr&#xff09;的捕获行为。 --capture 的选项值&#xff1a; fd&#xff08;默认&#xff09; 捕获文件描述符级别的输出&#xff08;stdout 和 stderr&#x…

整合SSM框架:构建Java Web应用

目录 简介 项目结构 配置文件详解 db.properties mybatis-config.xml spring-mybatis.xml springmvc.xml web.xml pom.xml 整合步骤 为什么这样整合&#xff1f; 简介 SSM框架整合指的是Spring、Spring MVC和MyBatis三个开源框架的整合。这种整合方式在Java Web开发…

Solidity开发智能合约

05-Solidity开发智能合约 0 Solidity和智能合约 Solidity开发可运行的智能合约步骤&#xff1a; 源代码通过编译成字节码&#xff08;Bytecode&#xff09;&#xff0c;同时会产生二进制接口规范&#xff08;ABI&#xff09; 通过交易将字节码部署到以太坊网络&#xff0c;部署…

Java基础之控制语句:开启编程逻辑之门

一、Java控制语句概述 Java 中的控制语句主要分为选择结构、循环结构和跳转语句三大类&#xff0c;它们在程序中起着至关重要的作用&#xff0c;能够决定程序的执行流程。 选择结构用于根据不同的条件执行不同的代码路径&#xff0c;主要包括 if 语句和 switch 语句。if 语句有…

Vue教程|搭建vue项目|Vue-CLI2.x 模板脚手架

一、项目构建环境准备 在构建Vue项目之前&#xff0c;需要搭建Node环境以及Vue-CLI脚手架&#xff0c;由于本篇文章为上一篇文章的补充&#xff0c;也是为了给大家分享更为完整的搭建vue项目方式&#xff0c;所以环境准备部分采用Vue教程&#xff5c;搭建vue项目&#xff5c;V…

shell脚本30个案例(五)

前言&#xff1a; 通过一个多月的shell学习&#xff0c;总共写出30个案例&#xff0c;分批次进行发布&#xff0c;这次总共发布了5个案例&#xff0c;希望能够对大家的学习和使用有所帮助&#xff0c;更多案例会在下期进行发布。 案例二十一、系统内核优化 1.问题&#xff1…

分布式集群下如何做到唯一序列号

优质博文&#xff1a;IT-BLOG-CN 分布式架构下&#xff0c;生成唯一序列号是设计系统常常会遇到的一个问题。例如&#xff0c;数据库使用分库分表的时候&#xff0c;当分成若干个sharding表后&#xff0c;如何能够快速拿到一个唯一序列号&#xff0c;是经常遇到的问题。实现思…

ChatGPT/AI辅助网络安全运营之-数据解压缩

在网络安全的世界中&#xff0c;经常会遇到各种压缩的数据&#xff0c;比如zip压缩&#xff0c;比如bzip2压缩&#xff0c;gzip压缩&#xff0c;xz压缩&#xff0c;7z压缩等。网络安全运营中需要对这些不同的压缩数据进行解压缩&#xff0c;解读其本意&#xff0c;本文将探索一…

C++小问题

怎么分辨const修饰的是谁 是限定谁不能被改变的&#xff1f; 在C中&#xff0c;const关键字的用途和位置非常关键&#xff0c;它决定了谁不能被修改。const可以修饰变量、指针、引用等不同的对象&#xff0c;并且具体的作用取决于const的修饰位置。理解const的规则能够帮助我们…

Docker中配置Mysql主从备份

Mysql配置主从备份 一、Docker中实现跨服务器主从备份二、配置步骤1.配置主库2.配置从库3.遇到问题3.其它使用到的命令 一、Docker中实现跨服务器主从备份 在 Docker 中配置 MySQL 主从备份主要通过 MySQL 主从复制实现 二、配置步骤 1.配置主库 # 进入mysql主库容器 docke…

下载maven 3.6.3并校验文件做md5或SHA512校验

一、下载Apache Maven 3.6.3 Apache Maven 3.6.3 官方下载链接&#xff1a; 二进制压缩包&#xff08;推荐&#xff09;: ZIP格式: https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.zipTAR.GZ格式: https://archive.apache.org/dist/…

C++趣味编程:基于树莓派Pico的模拟沙漏-倾斜开关与LED的互动实现

沙漏,作为一种古老的计时工具,利用重力让沙子通过狭小通道,形成了计时效果。在现代,我们可以通过电子元件模拟沙漏的工作原理。本项目利用树莓派Pico、倾斜开关和LED,实现了一个电子沙漏。以下是项目的详细技术解析与C++代码实现。 一、项目概述 1. 项目目标 通过倾斜开关…