SpringCloud-服务网关(Gateway)
Gateway
概述
https://github.com/Netflix/zuul/wiki
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/
SpringCloud中有个很重要的组件就是网关,在1.x版本中都使用Zuul;
但在2.x版本中,Zuul升级一直存在问题,SpringCloud自己研发了一个Gateway代替Zuul;
what
Gateway是在Spring生态系统上构建的API网关服务,基于Spring5.0+SpringBoot2+Project Reactor等技术,旨在提供一种简单有效的方式来对API进行路由、过滤(熔断、限流、重试等);
SpringCloud Gateway作为Spring Cloud生态中的网关,目标是代替Zuul;
在SpringCloud2.0以上版本,没有对新版本的Zuul2.x进行集成,仍然使用老版本的Zuul 1.x非Reactor模式;
为了提升网关性能,SpringCloud Gateway基于WebFlux实现(WebFlux底层使用高性能的Reactor模式的Netty);
有了Zuul,为什么还需要Gateway?
1、SpringCloud Gateway有如下特性:
基于Spring5.0+SpringBoot2+Project Reactor构建;
动态路由(能够匹配任何请求属性);
可以对路由指定Predicate和Filter;
集成Hystrix断路器功能;
集成SpringCloud服务发现功能;
易于编写的Predicate和Filter;
请求限流功能;
支持路径重写;
2、SpringCloud Gateway与Zuul区别:
Zuul1.x模型
Gateway模型
Gateway核心概念
Route路由
构建网关的基本模块;
由ID、目标URI、一系列的断言和过滤器组成;
Predicate断言
参考的是Java8的Predicate;
可以匹配HTTP请求的所有内容,如果请求与断言匹配则路由;
Filter过滤
指的是Spring中的GatewayFilter实例;
使用过滤器,可以在请求被路由前、路由后对请求进行修改;
Gateway工作流程
How
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> server: port: 9527 spring: application: name: gateway cloud: gateway: routes: - id: payment_route1 #路由ID(没有固定规则,但要求唯一,建议配合服务) uri: http://localhost:8001 #匹配后提供服务的路由地址 predicates: #断言(路径相匹配的进行路由) - Path=/get/** eureka: client: register-with-eureka: true #是否向注册中心注册自己 fetchRegistry: true #是否从注册中心抓取已有的注册信息 默认true,集群必须设置为true service-url: defaultZone: http://localhost:7001/eureka/ #单机版 @EnableEurekaClient @SpringBootApplication public class GatewayStarter9527 { public static void main(String[] args) { SpringApplication.run(GatewayStarter9527.class, args); } }
Java配置实现路由
@Configuration public class RouteConfig { @Bean public RouteLocator routeLocator1(RouteLocatorBuilder builder){ RouteLocatorBuilder.Builder routes = builder.routes(); routes.route("route1", r -> r.path("/guonei").uri("http://news.baidu.com/guonei") ).build(); return routes.build(); } } 访问http://localhost:9527/guonei,路由到http://news.baidu.com/guonei
通过微服务名实现动态路由
默认情况下,Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径 创建动态路由进行转发,从而实现动态路由;
server: port: 9527 spring: application: name: gateway cloud: gateway: discovery: locator: enable: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由 routes: - id: payment_route1 #路由ID(没有固定规则,但要求唯一,建议配合服务) #uri: http://localhost:8001 #匹配后提供服务的路由地址 uri: lb://eureka-payment-service #匹配后提供服务的路由地址(根据服务名动态路由) predicates: #断言(路径相匹配的进行路由) - Path=/get/** eureka: client: register-with-eureka: true #是否向注册中心注册自己 fetchRegistry: true #是否从注册中心抓取已有的注册信息 默认true,集群必须设置为true service-url: defaultZone: http://localhost:7001/eureka/ #单机版 http://localhost:9527/get/1
Predicates
RoutePredicateFactory
Spring Cloud Gateway matches routes as part of the Spring WebFlux HandlerMapping
infrastructure. Gateway的路由匹配 作为Spring WebFlux HandlerMapping的一部分;
Spring Cloud Gateway includes many built-in route predicate factories. Gateway内置很多自建的 route predicate factories;
All of these predicates match on different attributes of the HTTP request. 所有的predicates都与HTTP请求的不同属性 匹配;
You can combine multiple route predicate factories with logical and
statements. 多个route predicate factories可以组合使用;
Filter
GatewayFilter
Factories
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
Route filters allow the modification of the incoming HTTP request or outgoing HTTP response in some manner. filters允许修改HTTP请求、响应;
Route filters are scoped to a particular route. filters需要指定一个Route;
Spring Cloud Gateway includes many built-in GatewayFilter Factories. Gateway内置了很多 GatewayFilter Factories;
Global Filters
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#global-filters
自定义Global Filters
@Slf4j @Component public class GlobalLogFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String name = exchange.getRequest().getQueryParams().getFirst("name"); if (name == null){ log.warn("param error"); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } @Override public int getOrder() { return 0; } }