文章目錄
1:Gateway介紹
-
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 鏈的方式提供了網關基本的功能,例如:安全,監控/指標,和限流。
-
微服務架構中網關的位置圖
-
Gateway模型:WebFlux
傳統的Web框架,比如說: struts2, springmvc等都是基於Servlet API與Servlet容器基礎之上運行的。但是在Servlet3.1之後有了異步非阻塞的支持。而WebFlux是一個典型非阻塞異步的框架, 它的核心是基於Reactor的相關API實現的。相對於傳統的web框架來說,它可以運行在諸如Netty, Undertow及支持Servlet3.1的容器 上。非阻塞式+函數式編程(Spring5必須讓你使用java8)
2:Spring Cloud Gateway的特性
- 基於Spring Framework 5, Project Reactor和Spring Boot 2.0進行構建;
- 動態路由:能夠匹配任何請求屬性;
- 可以對路由指定Predicate (斷言)和Filter (過濾器) ;
- 集成Hystrix的斷路器功能;
- 集成Spring Cloud服務發現功能;
- 易於編寫的Predicate (斷言)和Filter (過濾器)
- 請求限流功能;
- 支持路徑重寫。
3:Gateway三大核心概念
Route(路由):路由是構建網關的基本模塊,它由ID,目標URI, 一系列的斷言和過濾器組成,如果斷言爲true則匹配該路由
Predicate(斷言):開發人員可以匹配HTTP請求中的所有內容(例如請求頭或請求參數),如果請求與斷言相匹配則進行路由
Filter(過濾):指的是Spring框架中GatewayFilter的實例,使用過濾器,可以在請求被路由前或者之後對請求進行修改。
如下圖所示工作流程
web請求,通過一些匹配條件,定位到真正的服務節點。並在這個轉發過程的前後,進行一些精細化控制。predicate就是我們的匹配條件;而filter, 就可以理解爲一個無所不能的攔截器。有了這兩個元素,再加上目標uri,就可以實現一個具體的路由了
4:Gateway工作流程
核心邏輯:路由轉發+執行過濾器鏈
工作步驟:
1:客戶端向Spring Cloud Gateway發出請求。然後在Gateway Handler Mapping中找到與請求相匹配的路由,將其發送到GatewayWeb Handler。
2:Handler再通過指定的過濾器鏈來將請求發送到我們實際的服務執行業務邏輯,然後返回。過濾器之間用虛線分開是因爲過濾器可能會在發送代理請求之前( “pre” )或之後( “post” )執行業務邏輯。
Filter在"pre"類型的過濾器可以做參數校驗、權限校驗、流量監控、日誌輸出、協議轉換等,在"post"類型的過濾器中可以做響應內容、響應頭的修改,日誌的輸出,流量監控等有着非常重要的作用。
5:Gateway搭建路由網關
第一步:配置pom.xml
<!-- gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
第二步:配置application.yml
server:
port: 9527
spring:
application:
name: cloud-getway
cloud:
gateway:
routes: # 路由器的id,沒有固定規則,但要求唯一,建議配合服務名
- id: payment_routh3
uri: http://cloud-provider-hystrix-payment# 匹配後提供服務的路由地址
predicates:
- Path=/payment/circuit/** # 斷言,路徑相匹配的進行路由
eureka:
instance:
hostname: cloud-gateway-service
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
第三步:測試
@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GatewayMain9527.class, args);
}
}
6:Gateway配置路由的兩種方式
第一種:在配置文件yml中配置
server:
port: 9527
spring:
application:
name: cloud-getway
cloud:
gateway:
routes:
# payment_route # 路由器的id,沒有固定規則,但要求唯一,建議配合服務名
- id: payment_routh
# 匹配後提供服務的路由地址
# uri: http://localhost:8001
uri: lb://CLOUD-PAYMENT-SERVICE
# 斷言,路徑相匹配的進行路由
predicates:
- Path=/payment/get/**
第二種:代碼中注入RouteLocator的Bean
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator routes(RouteLocatorBuilder builder){
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("path_route", r ->
r.path("/guonei")
.uri("http://news.baidu.com/guonei"));
return routes.build();
}
}
7:Gateway配置動態路由
- 默認情況下Gateway會根據註冊中心註冊的服務列表,以註冊中心上微服務名爲路徑創建動態路由進行轉發,從而實現動態路由的功能
修改application.yml配置文件,如下
discovery:
locator:
# 開啓從註冊中心動態創建路由的功能,利用微服務名進行路由
enabled: true
uri: lb://CLOUD-PAYMENT-SERVICE
server:
port: 9527
spring:
application:
name: cloud-getway
cloud:
gateway:
discovery:
locator:
# 開啓從註冊中心動態創建路由的功能,利用微服務名進行路由
enabled: true
routes:
# payment_route # 路由器的id,沒有固定規則,但要求唯一,建議配合服務名
- id: payment_routh
# 匹配後提供服務的路由地址
# uri: http://localhost:8001
uri: lb://CLOUD-PAYMENT-SERVICE
# 斷言,路徑相匹配的進行路由
predicates:
- Path=/payment/get/**
# payment_route2 # 路由器的id,沒有固定規則,但要求唯一,建議配合服務名
- id: payment_routh2
# 匹配後提供服務的路由地址
# uri: http://localhost:8001
uri: lb://CLOUD-PAYMENT-SERVICE
# 斷言,路徑相匹配的進行路由
predicates:
- Path=/payment/lb/**
- id: payment_routh3
uri: lb://cloud-provider-hystrix-payment
predicates:
- Path=/payment/circuit/**
eureka:
instance:
hostname: cloud-gateway-service
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
測試
8:Gateway的Predicate
springcloud組件gateway斷言(Predicate)
9:Gateway的自定義過濾器
- 在Spring-Cloud-Gateway之請求處理流程中最終網關是將請求交給過濾器鏈表進行處理。
核心接口:GatewayFilter,GlobalFilter,GatewayFilterChain。
- Spring Cloud Gateway 的 Filter 的生命週期有兩個:“pre” 和 “post”。
“pre”和 “post” 分別會在請求被執行前調用和被執行後調用,和 Zuul Filter 或 Spring Interceptor 中相關生命週期類似,但在形式上有些不一樣。
Zuul 的 Filter 是通過filterType()方法來指定,一個 Filter 只能對應一種類型,要麼是 “pre” 要麼是“post”。Spring Interceptor 是通過重寫HandlerInterceptor中的三個方法來實現的。而 Spring Cloud Gateway 基於 Project Reactor 和 WebFlux,採用響應式編程風格,打開它的 Filter 的接口GatewayFilter你會發現它只有一個方法filter。
-
實現自己的過濾器我們其實可以去查看Spring Cloud Gateway自帶過濾器源碼是如何實現的,
-
自定義過濾器比它自帶的好用
//此功能是看是否地址有uname的參數
@Component
@Slf4j
public class MyLogGatewayFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String uname=exchange.getRequest().getQueryParams().getFirst("uname");
if (uname==null){
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
/*
*過濾器存在優先級,order越大,優先級越低
*/
@Override
public int getOrder() {
return 0;
}
}