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;
}
}