GateWay使用手册

server/2024/12/27 8:09:55/

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


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  # 路由的唯一IDuri: lb://service_name  # 使用负载均衡访问注册到 Nacos 中的服务predicates:- Path=/user/**  # 请求路径以 `/user/` 开头时触发此路由filters:- AddRequestHeader=X-Request-Foo, Bar  # 添加请求头# 路由规则 2- id: service_name2uri: lb://service_name2predicates:- Path=/order/**  # 请求路径以 `/order/` 开头时触发此路由

4. 自定义全局过滤器

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

@Component  // 声明为Spring组件
public class MyGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 记录请求开始时间System.out.println("请求开始时间: " + System.currentTimeMillis());// 放行请求return chain.filter(exchange).then(Mono.fromRunnable(() -> {// 记录请求结束时间System.out.println("请求结束时间: " + System.currentTimeMillis());}));}@Overridepublic int getOrder() {// 过滤器的执行顺序,数字越小优先级越高return 0;}
}

5. 自定义Gateway过滤器

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

@Component
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {// 内部配置类,允许用户配置过滤器的参数@Datapublic static class Config {private String pattern = "yyyy-MM-dd";  // 设置默认日期格式private String message = "默认日志信息";  // 自定义日志信息}public MyGatewayFilterFactory() {super(Config.class);  // 指定配置类类型}@Overridepublic List<String> shortcutFieldOrder() {return List.of("pattern", "message");  // 设置快捷字段顺序}@Overridepublic 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_routeuri: lb://some-servicepredicates:- Path=/somepath/**  # 路径匹配条件filters:- name: My  # 使用自定义过滤器args:pattern: "yyyy-MM-dd~HH:mm:ss"  # 自定义日期格式message: "这是一个统计时间的gateway过滤器"  # 自定义日志信息

或者

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

案例1:登录检验

@Component
@EnableConfigurationProperties(AuthProperties.class)
public class AuthGlobalFilter implements GlobalFilter, Ordered {@Resourceprivate AuthProperties authProperties;@Resourceprivate JwtTool jwtTool;private final AntPathMatcher antPathMatcher = new AntPathMatcher();@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//1.获取requestServerHttpRequest request = exchange.getRequest();//2.判断路径是否需做登录拦截List<String> excludePaths = authProperties.getExcludePaths();if (isExclude(request.getPath())) {//此时不需要拦截,直接放行return chain.filter(exchange);}//3.获得tokenString token = request.getHeaders().getFirst("authorization");//4.检验并解析tokenLong userId = null;try {userId = jwtTool.parseToken(token);} catch (Exception e) {//设置响应状态码为401ServerHttpResponse 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;}@Overridepublic 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: gatewaycloud:nacos:discovery:server-addr: xiaotianlong.xyz:8848config: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和groupprivate final String dataId = "gateway-routes.json";private final String group = "DEFAULT_GROUP";// 保存已更新的路由IDprivate final Set<String> routeIds = new HashSet<>();@PostConstructpublic void initRouteConfigListener() throws NacosException {// 注册Nacos配置监听器并拉取配置String configInfo = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, 5000, new Listener() {@Overridepublic Executor getExecutor() {return null;  // 默认执行器为null}@Overridepublic 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.ppmy.cn/server/146246.html

相关文章

路由引入中次优路由和路由环路问题

A公司用的是IS-IS&#xff0c;B公司用的是OSPF&#xff0c;现在这两个公司要合并&#xff0c;网络要相通 项目目标 前期准备 配置IP地址&#xff1a;完成IP地址规划&#xff0c;A公司和B公司内部网络通过路由器R2和R4环回接口模拟。配置路由器接口的IP地址并测试所有直连链路的…

windows11 使用体验记录

好的地方&#xff1a; UI上字体风格貌似更好看了&#xff0c;文件夹增加了多个标签&#xff0c;类似于浏览器既可以打开多个窗口&#xff0c;也可以在同一个窗口中打开多个标签页 不好的地方&#xff1a; 桌面右下角点击日期时间&#xff0c;显示日期&#xff0c;时间呢&…

大语言模型LLM的微调中 QA 转换的小工具 xlsx2json.py

在训练语言模型中&#xff0c;需要将文件整理成规范的文档&#xff0c;因为文档本身会有很多不规范的地方&#xff0c;为了训练的正确&#xff0c;将文档进行规范处理。代码的功能是读取一个 Excel 文件&#xff0c;将其数据转换为 JSON 格式&#xff0c;并将 JSON 数据写入到一…

torch.set_default_device(device)

torch.set_default_device(device) device: 要设置为默认的设备 设置存储数据的默认设备&#xff08;默认是cpu&#xff0c;训练模型时&#xff0c;用gpu&#xff0c;以提高训练速度&#xff09; import torch # 打印当前所有可用的设备 # 检查CUDA是否可用 if torch.cuda.i…

Ubuntu下安装EMQTT

1、下载开源版地址,在下面的地址上没有找到windows版本的安装包。 https://www.emqx.com/zh/downloads-and-install/broker?osUbuntuubtuntu查询操作系统版本 lsb_release -aubuntu 查看操作系统结构arm还是x86 uname -m下载时&#xff0c;注意操作系统的版本&#xff0c;比如…

k8s容器存储接口 CSI 相关知识

容器存储接口 CSI 相关知识 参考&#xff1a; https://blog.csdn.net/lovely_nn/article/details/122880876 https://developer.aliyun.com/article/783464 https://www.cnblogs.com/varden/p/15139819.html存储商需实现 CSI 插件的 NodeGetVolumeStats 接口&#xff0c;Kube…

Linux操作系统学习---初识环境变量

目录 ​编辑 环境变量的概念&#xff1a; 小插曲&#xff1a;main函数的第一、二个参数 获取环境变量信息&#xff1a; 1.main函数的第三个参数 2.查看单个环境变量 3.c语言库函数getenv() 和环境变量相关的操作指令&#xff1a; 1.export---导出环境变量&#xff1a; 2.unse…

《数据结构》学习系列——图(下)

系列文章目录 目录 最短路径问题背景无权最短路径问题算法 正权最短路径问题迪杰斯特拉&#xff08;Dijkstra&#xff09;算法 每对顶点之间的最短路径 最小支撑树普利姆(Prim)算法伪代码 克鲁斯卡尔(Kruskal)算法时间复杂度 最短路径问题 背景 交通路线图&#xff1a; 顶点&…