最近做一个新项目,用到了Gateway
考虑到之后开发环境的的路由和线上的肯定不一致,而且后续可能会涉及到修改和新增路由信息
所以,动态路由是必须要上的,废话不多说,开车!
安装服务中心(注册中心)Nacos想要实现Gateway动态路由,服务中心是前置条件,在国内,现在最主流的服务中心,应该非Nacos莫属了
没安装的小伙伴,参考下我的这篇文章,安装过程非常简单
已经安装好了的,我们继续往下看
pom 依赖xml复制代码 <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>3.1.7</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.0.5.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2021.0.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>3.1.6</version>
</dependency>
yml 配置文件修改
修改前
properties复制代码server:
port: 8080
spring:
application:
name: my-gateway
cloud:
nacos:
# IP端口和用户名、密码
server-addr: 127.0.0.1:8868
username: nacos
password: nacos
gateway:
routes:
- id: api
# 匹配后,转发到此域名
uri: lb://api
# 匹配路径
predicates:
- Path=/api/**
# 过滤器配置
filters:
- StripPrefix=1
修改后
但等会儿我们实现了动态 routes 之后,.yml 文件里 routes就没有用了,我们可以把它注释或者删除 大家自行参考下方配置进行修改,新增的和注释的行,我都做有标记。
properties复制代码server:
port: 8080
spring:
application:
name: my-gateway
cloud:
nacos:
# IP端口和用户名、密码
server-addr: 127.0.0.1:8868
username: nacos
password: nacos
config:
# 禁用Spring的配置导入检查
import-check:
enabled: false
gateway:
discovery:
locator:
# 开启通过服务中心动态更新配置的功能
enabled: true
# routes:
# - id: api
# # 匹配后,转发到此域名
# uri: lb://api
# # 匹配路径
# predicates:
# - Path=/api/**
# # 过滤器配置
# filters:
# - StripPrefix=1
监听变更与更新路由配置
我们需要写一点java代码,监听Nacos上面的配置变更,然后更新路由信息
java复制代码
/**
* 路由信息变更监听
*/
@Component
@RefreshScope
public class OnRouteConfigChange implements ApplicationEventPublisherAware {
private static final Logger LOGGER = LoggerFactory.getLogger(OnRouteConfigChange.class);
/** 路由信息写入器 */
@Resource
private RouteDefinitionWriter routeDefinitionWriter;
/** 获取yml文件里nacos的配置信息 */
@Resource
private NacosConfigProperties nacosConfigProperties;
/** nacos 配置服务 */
private ConfigService configService;
/** 应用事件发布器 */
private ApplicationEventPublisher publisher;
/**
* 获取 nacos 配置服务
* @return
* @throws NacosException
*/
private ConfigService getConfigService() throws NacosException {
// 懒汉加载,用到再创建这个服务
if (null == configService){
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, nacosConfigProperties.getServerAddr());
properties.setProperty(PropertyKeyConst.USERNAME, nacosConfigProperties.getUsername());
properties.setProperty(PropertyKeyConst.PASSWORD, nacosConfigProperties.getPassword());
configService = NacosFactory.createConfigService(properties);
}
return configService;
}
/**
* 网关初始化
*/
@PostConstruct
public void initGatewayRoutes() {
try {
// 配置ID
String dateId = "my_gateway_route_config";
// 分组
String group = "MY_GATEWAY_ROUTE";
// 获取当前Nacos里,对应dataId的配置数据,随后开始监听对应dataId数据变更
String configjson = getConfigService().getConfigAndSignListener(dateId, group, nacosConfigProperties.getTimeout(), new Listener() {
@Override
public Executor getExecutor() { return null; }
/**
* 数据变更时触发
* @param configInfo 新的配置信息
*/
@Override
public void receiveConfigInfo(String configInfo) {
LoggerUtils.info(LOGGER, "监听到网关路由配置变更:{0}", configInfo);
saveRoutesConfig(configInfo);
}
});
LoggerUtils.info(LOGGER, "初始化网关路由配置:{0}", configJSON);
saveRoutesConfig(configJson);
} catch (Exception e) {
LoggerUtils.error(e, LOGGER, "初始化网关路由时发生错误", e);
}
}
/**
* 保存路由配置
* @param configJson
*/
private void saveRoutesConfig(String configJson){
List<RouteDefinition> definitions = JSONArray.parseArray(configJson, RouteDefinition.class);
if (!CollectionUtils.isEmpty(definitions)){
// 遍历更新路由信息
for (RouteDefinition definition : definitions){
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
}
// 发送刷新路由的事件通知
publisher.publishEvent(new RefreshRoutesEvent(this));
}
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
publisher = applicationEventPublisher;
}
}
在 Nacos 里配置路由信息
打开Nacos的控制台(我的Nacos端口配置成了8868,大家自行根据自己的端口配置来访问)
http://127.0.0.1:8868/nacos/
点击【创建配置】
如下图进行配置即可
配置内容信息,已经贴在下方了,大家可以自行复制参考
Data ID 和 Group 其实就是上面Java代码中的dateId和group,这里一定要对上,不然拉取不到配置
java复制代码 // 配置ID
String dateId = "my_gateway_route_config";
// 分组
String group = "MY_GATEWAY_ROUTE";
配置内容(JSON)
json复制代码 [
{
"id": "api",
"uri": "lb://api",
"predicates": [
{
"args": {
"pattern": "/api/**",
},
"name": "Path"
}
],
"filters": [
{
"args": {
"parts": 1
},
"name": "StripPrefix"
}
],
"order": 1
}
]
拓展知识:
验证是否成功1、配置内容是根据 org.springframework.cloud.gateway.route.RouteDefinition 的字段内容
2、args 里的内容,key名称可以随意设置,只要和这个args里的其他字段不重名就可以,它就是一个Map
例如 "pattern": "/api/**" 设置成 "pattern1": "/api/**",效果是一样的
3、args 里,如果想设置多个条件,加字段即可
例如 "args":{"pattern1": "/api/**", "pattern2": "/apis/**"}
为了能够比较直观的验证,我们重新【编辑】一下Nacos上面的配置内容
把uri改成 https://aliyun.com/,点击【发布】
然后,运行项目
在浏览器中输入:http://localhost:8080/api
成功进入了 aliyun.com 阿里云的页面,说明动态配置生效了
再试试改成 baidu.com ,和上面的步骤一样,编辑->修改uri->发布
然后刷新页面,和预期的一样,进入了百度的页面
搞定!
如果对您有帮助,请点个赞吧。
最后补充一个点
偶尔出现 gateway Failed to resolve 'xxx.com' after 5 queries 错误,过一会或者重启就好了,原因不清。
作者:大鹅coding
链接:https://juejin.cn/post/7239305332823982140