Gateway新一代網關
zuul路由網關
zuul核心人員走了兩個,zuul2的研發過久,spring公司等不及,自己研發的Gateway網關。
簡介
Cloud全家桶有個狠重要的組件就是網關,在1.x版本中都是採用Zuul網關;但是在2.x版本中,zuul的升級一致跳票,SpringCloud最後自己研發了一個網關替代Zuul, 那就是SpringCloud Gateway
- Gateway是在Spring生態之上構建的API網關服務,基於Spring 5,Spring Boot 2和Project Reactor 等技術。
- Gateway旨在提供一種簡單而有效 等方式來對API 進行路由,以及提供一些強大對過濾器,例如:熔斷、限流、重試等
- Gateway 作為SpringCloud 等目標提供統一等路由方式且基於Filter 鏈的方式提供了網關基本的功能,例如:安全,監控。限流
- SpringCloud Gateway 使用的Webflux中的 reactor-netty 響應式的編程,底層使用了Netty通訊框架
因為Zuul1.0 進入了維護階段,而且Gateway 是SpringCloud 團隊開發,比Zuul更加的便捷
Gateway 是基於異步非阻塞模型上進行開發的,性能方面不需要擔心
SpringCloud Gateway 與 Zuul 的區別
三大核心概念
Route (路由)
- 路由是構建網關的基本模塊,它由ID,目標URL,一系列的斷言和過濾器組成,如果斷言為true則匹配該路由
Predicate (斷言)
- 參考的是Java8的java.util.function.predicate
- 開發人員可以匹配HTTP請求中的所有內容(例如請求頭或請求參數),如果請求與斷言相匹配則進行路由
Filter (過濾)
- 指的是Spring框架中的GatewayFilter 的實例,使用過濾器,可以在請求被路由前或者之後請求進行修改。
總體
- web請求,通過一些匹配條件,定位到真正的服務節點。並在這個妝發過程的前後,進行一些精細化控制。
- predicate就是我們匹配條件;而filter ,就可以理解為一個無所不能的攔截器,有了這兩個元素,在加上目標uri,就可以實現一個具體的路由了
Gateway工作流程
(官網總結)
Demo
- 新建模塊cloud-gateway-gateway9527
- 引入pom
<dependencies>
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 引用自己定義的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.angenin.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--eureka client(通過微服務名實現動態路由)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</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>
- yml文件
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_route # 路由的id,沒有規定規則但要求唯一,建議配合服務名
uri: http://localhost:8001
predicates:
- Path=/payment/get/** # 斷言,路徑相匹配的進行路由
- id: payment_route2
uri: http://localhost:8001
predicates:
Path=/payment/lb/** #斷言,路徑相匹配的進行路由
eureka:
instance:
hostname: cloud-gateway-service
client:
fetch-registry: true
register-with-eureka: true
service-url:
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 client 8001 + Gateway 9527
通過我們 9527 網關訪問 8001的接口
這裡起到了作用
Gateway網關路由的兩種配置方式
- 在配置文件中配置
在配置文件yml中配置 - 在配置類中配置
代碼中注入RouteLocator的Bean
案例(訪問百度)
新建config.GatewayConfig
package com.yxl.cloud.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route("path_route_angenin", //id
r -> r.path("/guonei") //訪問 http://localhost:9527/guonei
.uri("http://news.baidu.com/guonei")); //就會轉發到 http://news.baidu.com/guonei
routes.route("path_route_angenin2", //id
r -> r.path("/guoji") //訪問 http://localhost:9527/guoji
.uri("http://news.baidu.com/guoji")); //就會轉發到 http://news.baidu.com/guonji
return routes.build();
}
}
訪問:http://localhost:9527/guonei
通過微服務名實現動態路由
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #開啟從註冊中心動態創建路由的功能,利用微服務名稱進行路由(默認false)
routes:
- id: payment_route #路由的id,沒有規定規則但要求唯一,建議配合服務名
# uri: http://localhost:8001 #匹配後提供服務的路由地址
uri: lb://cloud-provider-hystrix-payment
predicates:
- Path=/payment/get/** #斷言,路徑相匹配的進行路由
- id: payment_route2
# uri: http://localhost:8001
uri: lb://cloud-provider-hystrix-payment
predicates:
- Path=/payment/lb/** #斷言,路徑相匹配的進行路由
eureka:
instance:
hostname: cloud-gateway-service
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
Predicate的使用
SpringCloud Gateway 將路由匹配作為Spring WebFlux HandlerMapping 基礎架構的一部分。
SpringCloud Gateway 包括許多內置的Route Predicate工廠。所有這些Predicate 都與HTTP請求的不同屬性匹配。多個Route Predicate工廠可以進行組合
SpringCloud Gateway 創建Route 對象時,使用RoutePredicateFactory 創建 Predicate,Predicate 對象可以賦值給Route。Springcloud Gateway 包含許多內置的 Route Predicate Factories.
所有這些動詞 都匹配HTTP請求的不同屬性,多種謂詞工廠可以組合,通過邏輯and
簡單使用
public class T2 {
public static void main(String[] args) {
//獲取當前時間串
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);
//2020-06-17T11:53:40.325+08:00[Asia/Shanghai]
}
}
#指定時間前才能訪問(Before)
- Before=2020-06-17T11:53:40.325+08:00[Asia/Shanghai]
#指定時間內才能訪問(Between)
- Between=2020-06-17T11:53:40.325+08:00[Asia/Shanghai],2020-06-17T12:53:40.325+08:00[Asia/Shanghai]
Cookie
yml 設置 cookie
- Cookie=username,angenin #帶Cookie,並且username的值為angenin
不帶cookie 直接訪問失敗
Header
# - After=2020-06-17T12:53:40.325+08:00[Asia/Shanghai]
# - Cookie=username,angenin #帶Cookie,username的值為angenin
- Header=X-Request-Id, \d+ #請求頭要有 X-Request-Id屬性並且值為整數的正則表達式
Method
- Method=GET #只允許get請求訪問
總結
Filter的使用
路由過濾器可用於修改進入的HTTP請求和返回的HTTP響應,路由過濾器只能指定路由進行使用。
SpringCloud Gateway 內置了多種路由過濾器,他們都由GatewayFilter的工廠類來產生
GatewayFilter(31種)
Global Filter(10種)
package com.yxl.cloud.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
@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,非法用戶!!");
//設置響應,不被接受
exchange.getResponse().setStatusCode(HttpStatus.NO_CONTENT);
return exchange.getResponse().setComplete();
}
//返回chain.filter(exchange),放行
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
http://localhost:9527/payment/lb?xxx=111