官网地址:https://spring.io/projects/spring-cloud-gateway
中文文档参考:https://www.jianshu.com/p/6ff196940b67
1. Gateway 简介 Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于Netty、Reactor以及WEbFlux构建,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理
方式。 Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全
、监控
、埋点
和限流
等。
优点 性能强劲,是Zuul的1.6倍 功能强大,内置了很多实用的功能,例如转发、监控、限流等 设计优雅,容易扩展
缺点 依赖Netty与WebFlux,不是传统的Servlet编程模型,不能在Servlet容器下工作,也不能构建成WAR包,即不能将其部署在Tomcat、Jetty等Servlet容器里,只能打成jar包执行 不支持Spring Boot 1.x,需2.0及更高的版本
1.1 核心
Route(路由) 这是Spring Cloud Gateway的基本构建块,可简单理解成一条转发规则。包含:ID、目标URL、一组断言和一组过滤器可以根据规则进行匹配
Predicate(断言) 这是一个 Java 8 的 Predicate,即java.util.function.Predicate这个接口,Gateway使用Predicate实现路由的匹配条件
Filter(过滤器) 这是 org.springframework.cloud.gateway.filter.GatewayFilter 的实例,我们可以使用它修改请求和响应
客户端向Spring Cloud Gateway发出请求。如果Gateway Handler Mapping确定请求与路由匹配,则将其发送到Gateway Web Handler。此handler通过特定于该请求的过滤器链处理请求。图中filters被虚线划分的原因是filters可以在发送代理请求之前或之后执行逻辑。先执行所有“pre filter”逻辑,然后进行请求代理。在请求代理执行完后,执行“post filter”逻辑。
注意 HTTP和HTTPS URI默认端口设置是80和443。
1.2 路由匹配规则
1.3 官方配置文件 application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 spring: cloud: gateway: routes: - id: after_route uri: http://example.org predicates: - After=2017-01-20T17:42:47.789-07:00[America/Denver] spring: cloud: gateway: routes: - id: before_route uri: http://example.org predicates: - Before=2017-01-20T17:42:47.789-07:00[America/Denver] spring: cloud: gateway: routes: - id: between_route uri: http://example.org predicates: - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00 [America/Denver ]spring: cloud: gateway: routes: - id: cookie_route uri: http://example.org predicates: - Cookie=chocolate, ch.p spring: cloud: gateway: routes: - id: header_route uri: http://example.org predicates: - Header=X-Request-Id, \d+ spring: cloud: gateway: routes: - id: host_route uri: http://example.org predicates: - Host=**.somehost.org,**.anotherhost.org spring: cloud: gateway: routes: - id: method_route uri: http://example.org predicates: - Method=GET spring: cloud: gateway: routes: - id: host_route uri: http://example.org predicates: - Path=/foo/{segment},/bar/{segment} spring: cloud: gateway: routes: - id: query_route uri: http://example.org predicates: - Query=baz spring: cloud: gateway: routes: - id: remoteaddr_route uri: http://example.org predicates: - RemoteAddr=192.168.1.1/24
… … 更多过滤规则参考:https://www.jianshu.com/p/6ff196940b67
2. Gateway 应用 作为独立项目,承载请求的统一入口处理。
网关服务内部使用的 Netty 通信,发布的时候只能使用 jar 包
网关服务要部署在外网服务器
:对外。其他服务在内网服务器,除了邮件等…
依赖 jar
1 2 3 4 5 6 7 8 9 <dependency > <groupId > com.alibaba.cloud</groupId > <artifactId > spring-cloud-starter-alibaba-nacos-discovery</artifactId > <version > 2.2.1.RELEASE</version > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-gateway</artifactId > </dependency >
实现路由配置 application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 server: port: 80 spring: application: name: jerrygateway cloud: nacos: discovery: server-addr: 47.94 .193 .104 :8848 gateway: discovery: locator: enabled: true lower-case-service-id: true routes: - id: openapi uri: lb://jerryConsumer predicates: - Path=/open/** filters: - StripPrefix=1
配置启动类
1 2 3 4 5 6 7 @SpringBootApplication @EnableDiscoveryClient public class GatewayApplication { public static void main (String[] args) { SpringApplication.run(GatewayApplication.class,args); } }
测试 访问消费者的 swagger2 的 doc.html 需要使用路径:http://localhost/open/doc.html
open 为 Path=/open/** 中配置的访问路径匹配
3. Gateway 过滤器 全局过滤器 GlobalFilter、路由过滤器 GatewayFilter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 @Component @Slf4j public class VersionFilter implements GlobalFilter , Ordered { @Override public Mono<Void> filter (ServerWebExchange exchange, GatewayFilterChain chain) { log.info("过滤器----->" ); ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); response.setStatusCode(HttpStatus.BAD_REQUEST); response.getHeaders().add("Content-Type" , "text/html;charset=UTF-8" ); if (request.getQueryParams().containsKey("version" )) { double v = Double.parseDouble(request.getQueryParams().get("version" ).get(0 )); log.info("过滤器----->版本号:" + v); if (v == 1.0 ) { return chain.filter(exchange); } else { DataBuffer dataBuffer = response.bufferFactory().wrap(new JSONObject (R.fail("当前版本不支持,请尽快升级" )).toString().getBytes()); return response.writeWith(Mono.just(dataBuffer)); } } else { return chain.filter(exchange); } } @Override public int getOrder () { return 1 ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Component public class TokenFilter implements GatewayFilter , Ordered { @Override public Mono<Void> filter (ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("过滤器……" ); return chain.filter(exchange); } @Override public int getOrder () { return 0 ; } }@Configuration public class GatewayConfig { @Bean public RouteLocator createRL (RouteLocatorBuilder builder, TokenFilter tf) { return builder.routes().route(r -> r.path("/open/**" ). filters(f -> f.stripPrefix(1 ).filters(tf)). uri("lb://jerryConsumer" )).build(); } }
测试:访问消费者的 swagger2 的 doc.html 需要使用路径 http://localhost/open/doc.html