一、概述
1、是什么?
gateway是zuul1.x版的替代
GateWay是在Spring生态系统之上构建的API网关服务,基于Spring 5 , Spring Boot2 和 Project Reactor等技术。
SpringCloud Gateway使用的是Webflux中的react-netty响应式编程组件,底层使用了Netty通讯框架
GateWay旨在提供一种简单有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等
2、能干嘛?
反向代理
鉴权
流量监控
熔断
日志监控
3、服务架构中网关在哪?
网关是所有微服务的入口!!!
4、为什么选择Gateway?
5、SpringCloud Gateway 的特性?
6、SpringCloud Gateway与 Zuul的区别?
二、三大核心概念
Route(路由)
路由是构建网关的基本模块,它由ID,目标url,一系列的断言和过滤器组成,如果断言为true则匹配该路由
Predicate(断言)
参考java8的java.util.function.Predicate
开发人员可以匹配HTTP请求中的所有内容,如果请求和断言相匹配则进行路由
Filter(过滤)
指的是Spring框架中GateFilter的实例,使用过滤器,可以在请求被路由前,或者之后对请求进行修改
三、Gateway工作流程
四、Gateway入门配置 —— 实操
1)新建工程 cloud-gateway-gateway9527
2)pom文件
<dependencies>
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</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>
3)、yml配置
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心创建路由的功能,利用微服务进行路由
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
#- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
#- Cookie=username,zzyy
#- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
eureka:
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://localhost:7001/eureka
instance:
hostname: cloud-gateway-service
4)主启动类
@SpringBootApplication
@EnableEurekaClient
public class GatewayMain {
public static void main(String[] args) {
SpringApplication.run(GatewayMain.class,args);
}
}
5)配置类配置
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder rb){
RouteLocatorBuilder.Builder routes = rb.routes();
//访问 http://localhost:9527/guonei 将会转发到 http://news.baidu.com/guonei
routes.route("path_route_atguigu",
r -> r.path("/guonei").uri("http://news.baidu.com/guonei"))
.route("payment_routh",
r -> r.path("/payment/get/**").uri("http://localhost:8001/payment/get/**"));
return routes.build();
}
}
6)启动eureka7001 payment8001和gateway后访问 http://localhost:9527/payment/get/1,
也能得到payment8001服务提供的结果,说明网关起作用了
五、gateway网关配置的两种方法
1) 如上的yaml配置
2) java配置
增加配置类 GateWayConfig
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder rb){
RouteLocatorBuilder.Builder routes = rb.routes();
//访问 http://localhost:9527/guonei 将会转发到 http://news.baidu.com/guonei
routes.route("path_route_atguigu",
r -> r.path("/guonei").uri("http://news.baidu.com/guonei"))
.route("payment_routh",
r -> r.path("/payment/get/**").uri("http://localhost:8001/payment/get/**"));
return routes.build();
/* return null;*/
}
}
访问:http://localhost:9527/guonei , 说明配置类确实起作用了
六 、通过微服务名实现动态路由
默认情况下Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建路由转发,从而实现动态路由的功能
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心创建路由的功能,利用微服务进行路由
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址 lb:负载均衡的意思 cloud-payment-service:eureka注册中心的服务名
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
#- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
#- Cookie=username,zzyy
#- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
七、predicate的使用
常用的 Route Predicate
1、After Route Predicate
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
意思就是说在 2020-02-21T15:51:37之后访问的请求才有效
当时间改为:2022-02-21T15:51:37 访问出错:
2、Before Route Predicate
在 2020-02-21T15:51:37之前访问的请求才有效
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
- Before=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
3、Between Route Predicate
在 2020-02-21T15:51:37 ~ 2022-02-21T15:51:37这个时间段访问的请求才有效
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
- Between =2020-02-21T15:51:37.485+08:00[Asia/Shanghai],2022-02-21T15:51:37.485+08:00[Asia/Shanghai]
4、Cookie Router Predicate
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
- Cookie=username,zzyy
当没有携带cookie时:
携带cookie时
5、Header Router Predicate
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
- Header=X-Request-Id,\d+ # 请求头要有属性为X-Request-Id,并且值为整数的正则表达式
6、Host Router Predicate
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
- Host=*.atguigu.com # 该域名的网站发出的请求才能访问
7、Method Router Predicate
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
- Method=Get # get 请求才能放行
8、Query Router Predicate
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
- Query=userId,\d+ # 参数必须携带userId,且值必须为正整数
八、Filter的使用
1、是什么
路由过滤器可用于修改进入的Http请求和返回的Http响应,路由过滤器只能指定路由进行使用
SpringCloud Gateway内置了多种路由过滤器,他们都由GateWayFilter的工程类来产生
2、SpringCloud Gateway的Filter
3、常用的GatewayFilter
4、自定义过滤器
自定义全局 GlobalFilter:
必须携带userName参数,否则控制台会报错
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter,Ordered
{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
log.info("***********come in MyLogGateWayFilter: "+new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if(uname == null)
{
log.info("*******用户名为null,非法用户,o(╥﹏╥)o");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder()
{
return 0;
}
}