1、Getway
- SpringCloud Gateway 是 Spring Cloud 的一个全新项目,基于 Spring 5.0+Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
- SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 1.x非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty
- Spring Cloud Gateway的目标提供统一的路由方式且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
- 为什么选择Gatway
- Zuul1.0已经进入了维护阶段,而且Gatway是SpringCloud团队研发的
- Gatway是基于异步非阻塞模型上进行开发的,性能方面不需要担心。虽然Netflix早就发布了最新的Zuul2.x,但SpringCloud貌似没有整合计划
- SpringCloud Gatway具有以下特性
- 基于Spring Framework 5 ,Project Reactor 和 Spring Boot 2.0进行构建
- 动态路由:能够匹配任何请求属性
- 可以对路由指定Predicate(断言)和Filter(过滤器)
- 集成Hystrix的断路器功能
- 集成Spring Cloud服务发现功能
- 易于编写的Predicate(断言)和Filter(过滤器)
- 请求限流功能
- 支持路径重写
- Spring Cloud Gatway 和 Zuul的区别
- 在SpringCloud Finchley正式版之前,Sping Cloud 推荐的网关是Netflix提供的Zuul
- Zuul 1.x,是一个基于阻塞 I/O 的API Gatway
- Zuul 1.x 基于Servlet 2.5使用阻塞架构它不支持任何长连接(如WebSocket)Zuul的设计模式和Nginx较像,每次 I/O 操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是差别是Nginx用C++实现,Zuul用java实现,而JVM本身会有第一次加载较慢的情况,使得Zuul的性能相对较差
- Zuul 2.x 理念更先进,想基于Netty非阻塞和支持长连接,但Spring Cloud目前还没有整合。Zuul 2.x的性能较Zuul 1.x有较大的提升。
- Spring Cloud Gatway 建立在Spring Framework 5、Project Reactor 和Spring Boot 2 之上,使用非阻塞API
- Spring Cloud Gatway 还支持WebSocket,并且与Spring紧密集成拥有更好的开发体验
2、三大核心概念
- Route(路由)
- 路由是构建网关的基本模块,它由ID,目标URL,一系列的断言和过滤器组成,如果断言为true则匹配该路由
- Predicate(断言)
- 开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则则进行路由
- Filter(过滤)
- 指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改
3、Getway工作流程
- 客户端向Spring Cloud Gatway 发出请求。然后在Gatway Handler Mapping 中找到与请求相匹配的路由,将其发送到Gatway Web Handler
- Handler 再通过指定的过滤器链来讲请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会发送代理请求之前("pre")或之后("post")执行业务逻辑
- Filter在"pre"类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在"post"类型的过滤器中可以做响应内容、响应头的修改,日志输出,流量监控等非常重要的作用
4、Gatway服务搭建
- 新建cloud-gateway-gateway9527
- maven依赖
- application.yml
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/getPaymentById/** # 断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
- 启动类
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GateWayMain9527.class,args);
}
}
- 启动Eureka Server 7001
- 启动provider-8001
- 启动Gatway服务
- 访问provider-8001接口
- 使用网关访问provider-8001接口
- 使用配置类代替配置文件application.yml
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator2(RouteLocatorBuilder builder)
{
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("payment_routh",
r -> r.path("/payment/getPaymentById/**") // 断言
.uri("http://localhost:8001")).build(); // 匹配后提供服务的路由地址
return routes.build();
}
}
5、动态路由
- 通过微服务名实现动态路由
- 默认情况下Gatway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能
- 启动Eureka Server 7001
- 启动provider-8001
- 启动provider-8002
- Gateway application.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/getPaymentById/** # 断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
- lb://servicName是Spring Cloud gateway在微服务中自动为我们创建的负载均衡uri
6、常用的Route Predicate
- After Route Predicate
- 指定时间后
-Before Route Predicate - 指定时间前
- Between Route Predicate
- 指定时间区间
- Cookie Route Predicate
- 指定Cookie访问
- Header Route Predicate
- 指定请求头访问
- Host Route Predicate
- 指定主机地址
- Method Route Predicate
- 指定请求方式
- Path Route Predicate
- 指定请求路径
- Query Route Predicate
- 指定查询条件
- Predicate就是为了实现一组匹配规则让请求过来找到对应的Route进行处理
7、Filter
- 路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。
- Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生
- 声明周期
- pre
- post
- 种类
- GatewayFilter
- GlobalFilter
- 常用过滤器
- AddRequestParameter
- ...
spring:
cloud:
gateway:
routes:
filters:
# 过滤器工厂会在匹配的请求头加上一对请求头,名称为X-Request-Id值为1024
- AddRequestParameter=X-Request-Id,1024
- 自定义过滤器
- 编写配置类并实现 GlobalFilter,Ordered 两个接口
@Component
@Slf4j
public class MyLogGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("filter-------------------------");
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname == null){
System.out.println("****用户名为null,无法登录");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}