一:概念简介(技术选型-重要)
二:三大核心概念
三:Gateway 工作流程
四:入门配置
五:通过 微服务名 实现动态路由
六:Predicate 的使用
七:Filter 的使用
一:概念简介(技术选型-重要)
1)官网:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-starter
2)是什么:
a:Spring Cloud 全家桶中,有个很重要的组件,就是网关(Getway):在 1.x 版本中都是采用的 Zuul 网关。
b:2.x 中,使用 SpringCloud Getway 代替了 Zuul。
(netty视频:https://www.bilibili.com/video/BV1DJ411m7NR)(韩顺平)
c:一句话:SpringCloud Getway 使用的 WebFlux 框架实现的,而 WebFlux 框架底层使用了 高性能的 Reactor 模式通信框架 Netty;(异步非阻塞,性能高)
3)能干嘛:
a:反向代理:
b:鉴权:
c:流量控制:
d:熔断:重试、安全、
e:日志监控/指标:
f:。。。。。
4)微服务架构中,网关在哪里:(网关是 所有 为服务的 入口)
5)有 Zuul 了,怎么又来了 Getway:
a:为什么我们选择 Getway:
- SpringCloud Getway 特性:(Getway:异步非阻塞模型)
- SpringCloud Getway 与 Zuul 区别:
b:Zuul 1.x 模型:
c:GetWay 模型:(WebFlux)(异步非阻塞)
二:三大核心概念
1)Route(路由)概念:
2)Predicate(断言)概念:
3)Filter(过滤)概念:
4)总体:
三:Gateway 工作流程
1)官网总结
2)核心逻辑:路由转发 + 执行过滤链
四:入门配置
1)新建 Module:cloud-getway-getway-9527
2)POM:(不能有 web 依赖)
<dependencies>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3)YML:
server:
port: 9527
spring:
application:
name: cloud-getway-getway-9527
eureka:
instance:
hostname: cloud-getway-service
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
4)业务类:无
5)主启动类:
@EnableEurekaClient
@SpringBootApplication
public class GetwayGetway9527 {
public static void main(String[] args) {
SpringApplication.run(GetwayGetway9527.class, args);
}
}
6)9527 网关,如何做路由映射:
a:cloud-provider-payment-8001 看看Controller的 访问地址:(localhost:8001/getPayment?id=1)
b:我们不想暴露 8001 端口,希望在 8001 外面套一层 9527:
7)YML 新增网关配置:
server:
port: 9527
spring:
application:
name: cloud-getway-getway-9527
cloud:
gateway:
routes: # 路由:(id、目标URL、断言和过滤器)
- id: payment_route # 路由的 id:没有固定规则但要求 唯一,建议配合 服务名
uri: http://localhost:8001 # 断言 匹配后,提供服务的 路由地址
predicates: # 断言:请求 和 断言 匹配的,则进行路由
- Path=/getPayment/**
- id: payment_route_2
uri: http://localhost:8001
predicates:
- Path=/create/**
eureka:
instance:
hostname: cloud-getway-service
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
spring:
cloud:
gateway:
routes: // # 路由:(id、目标URL、断言和过滤器)
- id: payment_route // # 路由的 id:没有固定规则但要求 唯一,建议配合 服务名
uri: http://localhost:8001 // # 断言 匹配后,提供服务的 路由地址
predicates: // # 断言:请求 和 断言 匹配的,则进行路由
- Path=/getPayment/**
8)测试:
a:正常访问:(localhost:8001/getPayment?id=1)
b:通过网关访问:(localhost:9527/getPayment?id=1)(都能访问到)
9)YML 配置说明:
a:Getway 网关路由有两种配置方式:
1.在 配置文件 yml 中配置:(前面的配置)
2.代码中 注入 RouteLocator 的 Bean:(编码方式)
10)编码方式 进行 网关配置:
a:官网案例:
b:百度国内新闻地址,需要外网:
c:自己写一个:
@Configuration
public class GetwayConfig {
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder) {
// 访问: http://localhost:9527/guonei
// 跳转到:https://news.baidu.com/guonei
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route("path_route_baidu", (r) -> r.path("/guonei")
.uri("https://news.baidu.com/guonei")).build();
return routes.build();
}
}
五:通过 微服务名 实现动态路由
1)默认情况下:Getway 会根据注册中心注册的服务列表,以 注册中心上的微服务名称 为路径,创建 动态路由进行转发,从而实现动态路由功能。
2)启动:7001/7002 + 8001/8002 + getway
3)POM:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
4)YML:
spring:
application:
name: cloud-getway-getway-9527
cloud:
gateway:
discovery:
locator:
enabled: true # 开启从 注册中心,动态创建路由的功能,利用为服务名进行路由。
routes: # 路由:(id、目标URL、断言和过滤器)
- id: payment_route # 路由的 id:没有固定规则但要求 唯一,建议配合 服务名
uri: lb://CLOUD-PROVIDER-PAYMENT # 断言 匹配后,提供服务的 路由地址
predicates: # 断言:请求 和 断言 匹配的,则进行路由
- Path=/paymentInfo_OK/**
- id: payment_route_2
uri: lb://CLOUD-PROVIDER-PAYMENT
predicates:
- Path=/create/**
5)测试:(localhost:9527/getPayment?id=1)通过gateway 实现了 负载均衡。
六:跨域问题:
1)跨域问题:
a:跨域:指的是浏览器不能执行 其他网站脚本。它是由 浏览器 同源策略 造成的,是 浏览器对 JavaScript 施加的安全限制。
b:同源策略:协议、域名、端口;都要相同,其中有一个不同,就会产生跨域。
2)跨域流程:
3)解决跨域:(网关中统一配置跨域)
/**
* @author Zhang Xudong
* @date 2021/3/5 11:35 上午
*/
@Configuration
public class GuliMailCrosConfig {
@Bean
public CorsWebFilter corsWebFilter() {
UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
/* 配置跨域 */
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.setAllowCredentials(true);
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
CorsWebFilter corsWebFilter = new CorsWebFilter(urlBasedCorsConfigurationSource);
return corsWebFilter;
}
}
六:Predicate 的使用
1)是什么:启动 9527
a:启动中会显示如下:就有这么断言的方式。(11种)
2)Route Predicate Factories 是什么:
3)常用的 Route Predicate:
1.After:规定时间之后:2021-05-26T15:21:50.293+08:00[Asia/Shanghai]
--获取时间:
2.Before:规定时间之前
3.Between:规定区间时间之内
4.Cookie:规定携带什么样Cookie 才匹配:- Cookie=chocolate, ch.p(也就是 K:V)
测试:(curl http://localhost:9527/discover --cookie "username=zhangsan")
5.Header:规定携带什么样 Header 才匹配: - Header=X-Request-Id, \d+(K,V)
6.Host:根据主机进行拦截:- Host=**.somehost.org,**.anotherhost.org
7.Method:根据请求方法类型进行拦截:- Method=GET,POST:
8.Path:根据请求路径进行拦截:- Path=/red/{segment},/blue/{segment}
9.Query:带查询条件,要带参数查询条件,值为参数才进行拦截:- Query=red, gree
10.小总结:
- 说白了,Predicate 就是为了实现一组匹配规则,让请求过来,找到我们对应的路由,进行处理。
七:Filter 的使用
1)是什么:
2)SpringCloud Gateway 的 Filter:
a:生命周期,Only Two:
- pre:前置拦截
- post:后置拦截
b:种类,Only Two:(不需要,都是自定义类,实现借口)
- Gateway Filter:(31种之多)
- Global Filter:(10 种之多)
3)常见的 GatewayFilter:
4)自定义 过滤器:(自定义全局 Global Filter )
a:两个主要接口介绍:
- implements GlobalFilter ,Orderd
b:能干嘛:
- 全局日志记录:
- 统一网关鉴权(权限校验):
- 流量监控:
- 参数校验:
- 。。。。。
c:案例代码:(判断请求是不是每次都带着 username 参数)
- 自定义 日志实现类:继承两个接口:
@Slf4j
@Component
public class MyLogGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("come in MyLogGatewayFilter" + new Date());
String username = exchange.getRequest().getQueryParams().getFirst("username");
if (username == null) {
System.out.println("用户名为 null,非法");
exchange.getResponse().setStatusCode(HttpStatus.MULTI_STATUS);
return exchange.getResponse().setComplete();
}
//继续传下去
return chain.filter(exchange);
}
@Override
public int getOrder() {
//过滤链,数字越小,优先级越高。Ordered.HIGHEST_PRECEDENCE
return 0;
}
}
d:测试:(localhost:9527/getPayment?username=11)