Spring Cloud Gateway - 新一代微服務(wù)API網(wǎng)關(guān)
1.網(wǎng)關(guān)介紹
如果沒有網(wǎng)關(guān),難道不行嗎?功能上是可以的,我們直接調(diào)用提供的接口就可以了。那為什么還需要網(wǎng)關(guān)?
因為網(wǎng)關(guān)的作用不僅僅是轉(zhuǎn)發(fā)請求而已。我們可以試想一下,如果需要做一個請求認證功能,我們可以接入到 API 服務(wù)中。但是倘若后續(xù)又有服務(wù)需要接入,我們又需要重復(fù)接入。這樣我們不僅代碼要重復(fù)編寫,而且后期也不利于維護。
由于接入網(wǎng)關(guān)后,網(wǎng)關(guān)將轉(zhuǎn)發(fā)請求。所以在這一層做請求認證,天然合適。這樣這需要編寫一次代碼,在這一層過濾完畢,再轉(zhuǎn)發(fā)給下面的 API。
所以 API 網(wǎng)關(guān)的通常作用是完成一些通用的功能,如請求認證,請求記錄,請求限流,黑白名單判斷等。
API網(wǎng)關(guān)是一個服務(wù)器,是系統(tǒng)的唯一入口。
API網(wǎng)關(guān)方式的核心要點是,所有的客戶端和消費端都通過統(tǒng)一的網(wǎng)關(guān)接入微服務(wù),在網(wǎng)關(guān)層處理所有的非業(yè)務(wù)功能。通常,網(wǎng)關(guān)提供REST/HTTP的訪問API。
2.Spring Cloud Gateway介紹
Spring Cloud Gateway是Spring Cloud的新一代API網(wǎng)關(guān),基于WebFlux框架實現(xiàn),它旨在為微服務(wù)架構(gòu)提供一種簡單而有效的統(tǒng)一的API路由管理方式。
Spring Cloud Gateway作為Spring Cloud生態(tài)系統(tǒng)中的網(wǎng)關(guān),目標是替代Netflix ZUUL,具有更好的性能、更強的擴展性、以及更豐富的功能特性,其不僅提供統(tǒng)一的路由方式,并且基于Filter鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安全,監(jiān)控/埋點,限流等。
3.Spring Cloud Gateway的特性
- 基于Spring Framework 5, Project Reactor和Spring Boot 2.0
- 動態(tài)路由:能夠匹配任何請求屬性
- 可以對路由指定 Predicate 和 Filter
- 集成Hystrix斷路器
- 集成Spring Cloud DiscoveryClient 服務(wù)發(fā)現(xiàn)功能
- 易于編寫的Predicate和Filter
- 請求限流
- 支持路徑重寫
4.Spring Cloud Gateway的三大核心概念
路由(Route):路由是網(wǎng)關(guān)最基礎(chǔ)的部分,路由信息由一個ID,一個目標URI,一組斷言和過濾器組成。路由斷言Predicate用于匹配請求,過濾器Filter用于修改請求和響應(yīng)。如果斷言為true,則說明請求URI和配置匹配,則執(zhí)行路由。
spring:
cloud:
gateway:
# 定義多個路由
routes:
# 一個路由route的id
- id: path_route
# 該路由轉(zhuǎn)發(fā)的目標URI
uri: https://example.org
# 路由條件集合
predicates:
- Path=/test/**
# 過濾器集合
filters:
- AddRequestHeader=X-Request-Id, 1024
- AddRequestParameter=color, red
斷言(Predicate):參考Java8中的斷言Predicate,用于實現(xiàn)請求匹配邏輯,例如匹配路徑、請求頭、請求參數(shù)等。請求與斷言匹配則執(zhí)行該路由。
過濾器(Filter):指的是Spring框架中GatewayFilter的實例,使用過濾器,可以在請求被路由前后對請求進行修改。
5.Gateway工作流程
客戶端向Spring Cloud Gateway發(fā)出請求,然后在Gateway Handler Mapping中找到與請求相匹配的路由,將其發(fā)送到Gateway Web Handler。Handler再通過指定的過濾器鏈來對請求進行過濾處理,最后發(fā)送到我們實際的服務(wù)執(zhí)行業(yè)務(wù)邏輯,然后返回。
過濾器鏈被虛線分隔,是因為過濾器既可以在轉(zhuǎn)發(fā)請求前攔截請求,也可以在請求處理之后對響應(yīng)進行攔截處理。
6.Gateway核心配置
依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
啟動類
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
application.yml
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
# 路由的ID,沒有固定規(guī)則但要求唯一,建議配合服務(wù)名
- id: config_route
# 匹配后提供服務(wù)的路由地址
uri: http://ityouknow.com
# 斷言,路徑相匹配的條件
predicates:
- Path=/routeconfig/rest/**
- id: header_route
uri: http://ityouknow.com
predicates:
- Header=X-Request-Id, \d+
7.動態(tài)路由
網(wǎng)關(guān)接收外部請求,按照一定的規(guī)則,將請求轉(zhuǎn)發(fā)給其他服務(wù)或者應(yīng)用。如果站在服務(wù)調(diào)用的角度,網(wǎng)關(guān)就扮演著服務(wù)消費者的角色,此時,如果再來看看服務(wù)調(diào)用的目標URI配置,就會很自然的發(fā)現(xiàn)一個問題,服務(wù)提供者調(diào)用的地址是寫死的,即網(wǎng)關(guān)沒有動態(tài)的發(fā)現(xiàn)服務(wù),這就涉及到了服務(wù)的自動發(fā)現(xiàn)問題,以及發(fā)現(xiàn)服務(wù)后,所涉及到的服務(wù)調(diào)用的負載均衡的問題。
可以通過Nacos或者Eureka注冊中心動態(tài)發(fā)現(xiàn)服務(wù),通過Ribbon進行服務(wù)調(diào)用的負載均衡。同樣,Gateway也可以整合Nacos或者Eureka,Ribbon從而實現(xiàn)動態(tài)路由的功能。
想要使用動態(tài)路由的功能,首先要整合注冊中心,這里以Nacos為例
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
spring:
application:
name: cloud-gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
routes:
#路由的ID,沒有固定規(guī)則但要求唯一,建議配合服務(wù)名
- id: config_route
#匹配后提供服務(wù)的路由地址, 這里lb之后,跟的是要調(diào)用的服務(wù)名稱
uri: lb://nacos-provider-8002
# 斷言,路徑相匹配的條件
predicates:
- Path=/routeconfig/rest/**
此時,當id為config_route的路由規(guī)則匹配某個請求后,在調(diào)用該請求對應(yīng)的服務(wù)時,就會從nacos注冊中心自動發(fā)現(xiàn)服務(wù),并在服務(wù)調(diào)用的時候?qū)崿F(xiàn)負載均衡。
8.Predicate
在Gateway中,有一些的內(nèi)置Predicate Factory,有了這些Pridicate Factory,在運行時,Gateway會 自動根據(jù)需要創(chuàng)建其對應(yīng)的Pridicate對象測試路由條件。
-
Path 路由斷言 Factory:根據(jù)請求路徑匹配的路由條件工廠
spring: cloud: gateway: routes: - id: path_route uri: https://example.org predicates: # 如果可以匹配的PathPattern有多個,則每個路徑模式以,分開 - Path=/red/{segment},/blue/{segment}
-
After 路由斷言 Factory:在指定日期時間之后發(fā)生的請求都將被匹配
spring: cloud: gateway: routes: - id: after_route uri: https://example.org predicates: - After=2017-01-20T17:42:47.789-07:00[America/Denver]
-
Cookie 路由斷言 Factory
Cookie 路由斷言 Factory有兩個參數(shù),cookie名稱和正則表達式。請求包含此cookie名稱且正則表達式為真的將會被匹配。
spring: cloud: gateway: routes: - id: cookie_route uri: https://example.org predicates: - Cookie=chocolate, ch.p
-
Header 路由斷言 Factory
Header 路由斷言 Factory有兩個參數(shù),header名稱和正則表達式。請求包含此header名稱且正則表達式為真的將會被匹配。
spring: cloud: gateway: routes: - id: header_route uri: https://example.org predicates: - Header=X-Request-Id, \d+
-
Host 路由斷言 Factory
Host 路由斷言 Factory包括一個參數(shù):host name列表。使用Ant路徑匹配規(guī)則, . 作為分隔符。
spring: cloud: gateway: routes: - id: host_route uri: https://example.org predicates: - Host=**.somehost.org,**.anotherhost.org
-
Method 路由斷言 Factory
Method 路由斷言 Factory只包含一個參數(shù):需要匹配的HTTP請求方式
spring: cloud: gateway: routes: - id: method_route uri: https://example.org predicates: - Method=GET
自定義Predicate
可以自定義Predicate來實現(xiàn)復(fù)雜的路由匹配規(guī)則:
// 實現(xiàn)自定義 Predicate 工廠
// 通過HostRoutePredicateFactory創(chuàng)建Predicate進行路由判斷
@Component
public class MyHostRoutePredicateFactory extends AbstractRoutePredicateFactory<MyHostRoutePredicateFactory.Config> {
public MyHostRoutePredicateFactory() {
// Config 類作為 Predicate 的配置參數(shù)類
super(Config.class);
}
public static class Config {
// 路由匹配規(guī)則
private String hostName;
public String getHostName() {
return hostName;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}
}
// 生成一個 Predicate 實例
@Override
public Predicate<ServerWebExchange> apply(Config config) {
// 實現(xiàn)匹配邏輯
return exchange -> {
// 根據(jù)config實現(xiàn)匹配判斷
String host = exchange.getRequest().getURI().getHost();
// 匹配配置中的域名
return host.equals(config.getHostName());
};
}
}
// 使用
RouteLocator locator = new RouteLocatorBuilder(router)
.routes()
.route("test_route", r -> r.path("/test")
.filters(f -> f.filter(new MyHostRoutePredicateFactory.Config("www.test.com")))
.uri("http://localhost:8080"))
.build();
9.自定義Filter
可以通過實現(xiàn)GatewayFilter和Ordered接口自定義Filter來實現(xiàn)請求處理邏輯:文章來源:http://www.zghlxwxcb.cn/news/detail-599796.html
@Component
public class TokenFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//請求處理邏輯
log.info("請求路徑:"+ exchange.getRequest().getPath());
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, HttpCookie> cookies = request.getCookies();
List<HttpCookie> tokens = cookies.get("access_token");
if (tokens == null || tokens.size() == 0) {
throw new RuntimeException("少了cookie!");
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
10.默認過濾器
Spring Cloud Gateway內(nèi)置了多種過濾器,例如:文章來源地址http://www.zghlxwxcb.cn/news/detail-599796.html
- AddRequestHeader GatewayFilter:在請求頭中添加參數(shù)
- PrefixPath GatewayFilter:請求路徑前綴
- Hystrix GatewayFilter: 斷路器
- RateLimit GatewayFilter: 限流
- Retry GatewayFilter: 重試
到了這里,關(guān)于Spring Cloud Gateway - 新一代微服務(wù)API網(wǎng)關(guān)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!