一文搞定zuul使用
- 2021 年 4 月 13 日
- 筆記
- SpringCloud, 微服務
前言
在深入探討Spring Cloud Gateway的細節之前,讓我們了解有關反向代理和api網關模式的一些基礎知識。
什麼是反向代理?
反向代理是代表其他事物進行請求的事物。它的行為更像是簡單的路由。它可以增加基本的安全性和監視功能,但實際上不能做某些高級事情,例如中介或業務流程。NGINX是眾所周知的反向代理伺服器之一。
什麼是API網關?
簡而言之,API Gateway是增強的反向代理,具有更高級的功能,包括編排以及增加的安全性和監視功能。Netflix Zuul(上文介紹),Amazon API Gateway,Apigee以及Spring Cloud Gateway當然是少數著名的api網關實現。
Spring Cloud Gateway主要功能:
-
建立在Spring Framework 5,Project Reactor(後面我會單獨開篇幅去介紹reactor3)和Spring Boot 2.0之上
-
能夠匹配任何請求屬性上的路由。
-
謂詞和過濾器特定於路由。
-
斷路器集成。
-
Spring Cloud DiscoveryClient集成
-
易於編寫的謂詞和過濾器
-
請求速率限制
-
路徑改寫
Spring Cloud Gateway 對比 Zuul
-
我知道所有使用Spring Boot的人都想知道,我們已經在使用Zuul。它幾乎提供了與Spring Cloud Gateway相同的功能。那麼,為什麼我們要切換到新框架?對我來說,主要原因是Zuul 1.x沒有反應式編程。它使用阻塞api。現在,如果您正在遷移到Reactive模式以從微服務中獲得更好的性能,並且您將Spring Boot 2與Reactor一起使用。
-
您可以使用Zuul 2.0,它確實具有Netty的Reactive nonblocking支援。 但是Spring生態系統沒有像Zuul 1.x那樣給予Zuul 2.0的內置支援,這意味著,您必須使用Zuul運行自己的獨立服務。你不能讓它與其他現有的spring微服務集成。Spring團隊並不打算用Spring來增加對它的支援。
-
所以Spring Cloud Gateway可以與任何微服務集成,使之成為真正的api網關,在一個地方添加身份驗證和其他安全功能。因為推薦使用Spring Cloud Gateway。
Spring Cloud Gateway簡介
Spring Cloud Gateway是Spring Cloud團隊在Spring反應生態系統(Webflux)之上的API網關實現。它提供了一種簡單有效的方法,即使用網關處理程式映射將傳入的請求路由到適當的目的地。Spring Cloud Gateway使用Netty伺服器提供非阻塞非同步請求處理。以下是在Spring Cloud Gateway中請求路由的工作原理的高層流程:

Spring Cloud Gateway包含3個主要構建模組:
-
Route(路由)
將此視為我們希望將特定請求路由到的目的地。它由目標URI、必須滿足的條件或技術術語、謂詞和一個或多個篩選器組成。
-
Predicate(謂詞)
這實際上是一個需要匹配的條件。 例如if條件。如果請求有某些東西-例如,path=blah或請求頭包含foo-bar等。在java技術術語中,它類似於java8函數謂詞Predicate
。 具體謂詞類型參考文檔:
//docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories
-
Filter(過濾器)
這些是springframeworkwebfilter的實例。在這裡您可以應用修改請求或響應的魔力。框架提供了很多現成的WebFilter。當然,我們討論的是Spring框架。所以,大家休息吧!!!您始終可以使用自己的邏輯添加自己的篩選器。
Spring Cloud Gateway 原理
Spring Cloud Gateway 的工作原理跟 Zuul 的差不多,最大的區別就是 Gateway 的 Filter 只有 pre 和 post 兩種。下面我們簡單了解一下 Gateway 的工作原理圖,如下圖所示。

-
Predicate 原理
Predicte由PredicateSpec來構建,主要實現有:

以PathRoutePredicateFactory為例看下源碼:
@Override
public Predicate<ServerWebExchange> apply(Config config) {
final ArrayList<PathPattern> pathPatterns = new ArrayList<>();
synchronized (this.pathPatternParser) {
pathPatternParser.setMatchOptionalTrailingSeparator(config.isMatchOptionalTrailingSeparator());
config.getPatterns()
.forEach(pattern -> {
// 構建匹配規則
PathPattern pathPattern = this.pathPatternParser.parse(pattern);
pathPatterns.add(pathPattern);
})
;
}
return exchange -> {
PathContainer path = parsePath(exchange.getRequest().getURI().getPath());
// 匹配過濾
Optional<PathPattern> optionalPathPattern = pathPatterns.stream().filter(pattern -> pattern.matches(path)).findFirst();
if (optionalPathPattern.isPresent()) {
// 如果存在匹配成功的 然後設置匹配成功的PathMatchInfo
PathPattern pathPattern = optionalPathPattern.get();
traceMatch("Pattern", pathPattern.getPatternString(), path, true);
PathMatchInfo pathMatchInfo = pathPattern.matchAndExtract(path);
putUriTemplateVariables(exchange, pathMatchInfo.getUriVariables());
return true;
} else {
traceMatch("Pattern", config.getPatterns(), path, false);
return false;
}
};
}
-
Filter 原理
Filter分兩種,一種GatewayFilter(網關路由過濾器),一種GlobalFilter(全局路由器)
- GlobalFilter
為請求業務以及路由的URI轉換為真實業務服務的請求地址的核心過濾器,不需要配置,模式系統初始化時載入,並作用在每個路由上。-
GatewayFilter
Gateway內置了不少可用的GatewayFilter,具體如下:
GatewayFilter 下面以OrderedGatewayFilter為例子看下源碼:
/**
* 排序的網關路由過濾器,用於包裝真實的網關過濾器,已達到過濾器可排序
*/
public class OrderedGatewayFilter implements GatewayFilter, Ordered {
//目標過濾器
private final GatewayFilter delegate;
//排序欄位
private final int order;
public OrderedGatewayFilter(GatewayFilter delegate, int order) {
this.delegate = delegate;
this.order = order;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 讓下個過濾器過濾
return this.delegate.filter(exchange, chain);
}
}
具體GatewayFilter類型參考文檔: `//docs.spring.io/spring-cloud-gateway/docs/2.2.8.BUILD-SNAPSHOT/reference/html/#gatewayfilter-factories` -
Spring Cloud Gateway 入門
-
###引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
-
使用RouteLocator去構建url路由
@SpringBootApplication
public class GatewayClientApplication {
@Value("${test.uri}")
private String uri;
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
//basic proxy
.route(r -> r.path("/order/**")
.uri(uri)
).build();
}
public static void main(String[] args) {
SpringApplication.run(GatewayClientApplication.class, args);
}
}
-
application.ymal方式
假設test1-service和test2-service的服務地址分別是//127.0.0.1:8070,//127.0.0.1:8060
例如下面的寫法中,test1-service最終轉發後的路徑就是://127.0.0.1:8070/** 去除了test1-service路徑
test2-service最終路徑 ://127.0.0.1:8060/test2-service/** 不做路徑剝離直接請求。
spring:
application:
name: gateway
cloud:
gateway:
discovery:
locator:
lowerCaseServiceId: true
enabled: true
routes:
- id: test-1
uri: lb://test1-service #負載均衡url
order: 8001 #定義順序
predicates: #謂詞
- Path=/test1-service/**
filters: #過濾器
- AddResponseHeader=X-Response-test1, test1
- id: test-2
uri: lb://test2-service
order: 8003
predicates:
- Path=/test2-service/oauth/token
filters:
- AddResponseHeader=X-Response-test2, test2
END
下篇詳細介紹 Spring Cloud Gateway 高級用法
歡迎關注公眾號!
公眾號回復:入群
,掃碼加入我們交流群!