微服务实战(六) Gateway 网关
概述
在微服务众多的服务的治理过程中,服务网关的作用在微服务框架中可以提供统一入口
、鉴权校验
、动态路由
、降低耦合度
的功能,关于springcloud的网关有三个,分别是zuul、zuul2和gateway,其中zuul/zuul2是Netflix公司开发的,但是因为zuul的性能不够好,zuul2的开发内部有歧义,所以springcloud便自研了一套网关——gateway。
Spring Cloud Gateway 作为 Spring Cloud 生态系中的网关,其目标是替代 Netflix Zuul,它不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全、监控/埋点和限流等。
概念
-
Route
Route 是网关的基础元素,由 ID、目标 URI、断言、过滤器组成。当请求到达网关时,由 Gateway Handler Mapping 通过断言进行路由匹配(Mapping),当断言为真时,匹配到路由。
-
Predicate
Predicate 是 Java 8 中提供的一个函数。输入类型是 Spring Framework ServerWebExchange。它允许开发人员匹配来自 HTTP 的请求,例如请求头或者请求参数。简单来说它就是匹配条件。
-
Filter
Filter 是 Gateway 中的过滤器,可以在请求发出前后进行一些业务上的处理。
工作原理
- 客户端向Spring Cloud Gateway发出请求,然后在
Gateway Handler Mapping
中找到与请求相匹配的路由,将其发送到Gateway web hander
- Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前( “pre” )或之后( “post” )执行业务逻辑。
- Filter在"pre” 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在"post"类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。
Gateway+Nacos 实现动态路由
添加POM
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
添加配置
server:
port: 8080
spring:
application:
name: sunnyws-gateway
profiles:
active: dev
cloud:
nacos:
discovery:
server-addr: 172.16.220.50:8848
namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
gateway:
discovery:
locator:
enabled: true
gateway:
nacos:
serverAddr: 172.16.220.50:8848
namespace: e90d261b-9c05-4bcb-b99f-b419d952737a
dataId: dynamic-route
timeout: 5000
添加配置类
- Nacos配置类
@Data
@ConfigurationProperties(prefix = "gateway.nacos")
public class NacosProperties {
private String serverAddr;
private String namespace;
private String group = "DEFAULT_GROUP";
private String dataId = "dynamic-route";
private long timeout = 5000;
}
@Data
public class GatewayRouteList {
private List<RouteDefinition> routes;
}
- 从Nacos上初始化路由并动态监听
@Slf4j
@Configuration
public class DynamicRouteNacosConfiguration {
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
@Autowired
private NacosProperties nacosProperties;
@PostConstruct
public void initRoute() {
try {
Properties properties = new Properties();
properties.put("serverAddr", nacosProperties.getServerAddr());
properties.put("namespace", nacosProperties.getNamespace());
ConfigService configService = NacosFactory.createConfigService(properties);
String content = configService.getConfig(nacosProperties.getDataId(), nacosProperties.getGroup(), nacosProperties.getTimeout());
log.info("初始化网关路由开始");
updateRoute(content);
log.info("初始化网关路由完成");
//开户监听,实现动态
configService.addListener(nacosProperties.getDataId(), nacosProperties.getGroup(), new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
log.info("更新网关路由开始");
updateRoute(configInfo);
log.info("更新网关路由完成");
}
@Override
public Executor getExecutor() {
return null;
}
});
} catch (NacosException e) {
log.error("加载路由出错:{}", e.getErrMsg());
}
}
/**
* @description: 更新路由
* @param content
* @return void
**/
private void updateRoute(String content){
Yaml yaml = new Yaml();
GatewayRouteList gatewayRouteList = yaml.loadAs(content, GatewayRouteList.class);
gatewayRouteList.getRoutes().forEach(route -> {
log.info("加载路由:{},{}", route.getId(), route);
routeDefinitionWriter.save(Mono.just(route)).subscribe();
});
}
}
- 添加跨域配置
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 允许cookies跨域
config.setAllowCredentials(true);
// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
config.addAllowedOrigin("*");
// #允许访问的头信息,*表示全部
config.addAllowedHeader("*");
// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
config.setMaxAge(18000L);
// 允许提交请求的方法类型,*表示全部允许
config.addAllowedMethod("*");
// config.addAllowedMethod("OPTIONS");
// config.addAllowedMethod("HEAD");
// config.addAllowedMethod("GET");
// config.addAllowedMethod("PUT");
// config.addAllowedMethod("POST");
// config.addAllowedMethod("DELETE");
// config.addAllowedMethod("PATCH");
org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource source =
new org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
-
启动类添加
@EnableDiscoveryClient
允许注册到Nacos -
启动类添加
@EnableConfigurationProperties
注入Nacos配置
@EnableDiscoveryClient
@SpringBootApplication
@EnableConfigurationProperties(NacosProperties.class)
public class GateWayApplication {
public static void main(String[] args) {
SpringApplication.run(GateWayApplication.class,args);
}
}
Nacos添加配置
- 根据Nacos配置及需求添加配置
这只是gateway的基本使用,也可结合前面介绍的sentinel和ribbon实现负载均衡和限流。
作者: SunnyWs
链接: https://sunnyws.com/posts/f8ec904c/
来源: SunnyWs’Blog