Spring Cloud Gateway 基於WebFlux框架使用非阻塞API。它主要透過路由定義來決定請求如何被處理。每個路由可以指定一個或多個過濾器,這些過濾器可以修改請求和響應。
前置過濾器:這些過濾器在請求實際被路由到下游服務之前執行。它們可以用來修改請求頭、查詢引數、驗證請求等。
後置過濾器:這些過濾器在請求被下游服務處理之後執行,通常用於修改響應或進行日誌記錄。
簡單概念
過濾器工作流程
在Spring Cloud Gateway中,請求經過以下幾個步驟:
請求匹配:判斷請求是否匹配某個路由的條件。
前置過濾器執行:執行所有前置過濾器,可能修改請求。
請求路由:將請求轉發到相應的下游服務。
後置過濾器執行:在得到下游服務響應後執行,可能修改響應。
原始碼解析
我們將看看關鍵的類和介面:
GatewayFilter:所有自定義過濾器需要實現這個介面,它定義了一個方法,該方法接受ServerWebExchange和GatewayFilterChain。
GlobalFilter:一種特殊型別的GatewayFilter,自動應用於所有路由。
ServerWebExchange:代表當前請求和響應的上下文,可以用來訪問和修改請求和響應。
以下是一個簡單的前置過濾器示例的虛擬碼:
public class ExamplePreFilter implements GatewayFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 訪問請求物件 ServerHttpRequest request = exchange.getRequest(); // 修改請求(例如:新增頭資訊) ServerHttpRequest modifiedRequest = request.mutate().header("New-Header", "Value").build(); // 將修改後的請求物件傳遞給下一個過濾器鏈 return chain.filter(exchange.mutate().request(modifiedRequest).build()); } @Override public int getOrder() { // 定義過濾器順序 return -1; } }
後置過濾器的示例虛擬碼:
public class ExamplePostFilter implements GatewayFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 繼續過濾器鏈的執行 return chain.filter(exchange).then(Mono.fromRunnable(() -> { // 訪問響應 ServerHttpResponse response = exchange.getResponse(); // 修改響應(例如:新增頭資訊) response.getHeaders().add("Post-Header", "Value"); })); } @Override public int getOrder() { // 定義過濾器順序 return 1000; } }
在Spring Cloud Gateway的原始碼中,這些類和介面被實現和使用,以提供強大的路由和過濾功能。每個過濾器的執行都是非同步和非阻塞的,利用的是Project Reactor提供的反應式程式設計模型。
在Spring Boot中使用Spring Cloud Gateway的前置過濾器和後置過濾器的示例可以應用於許多實際場景。以下是一個具體的例子,我們將構建一個閘道器,它使用前置過濾器來校驗請求中的API金鑰,並使用後置過濾器來新增一些響應頭資訊。
場景例項
場景描述
假設我們有一個需要保護的微服務,只有提供了有效的API金鑰的請求才能訪問。我們還想在所有響應中新增一些標準的HTTP頭,比如一個標識服務的自定義頭。
步驟1: 設定Spring Boot和Spring Cloud Gateway
首先,確保你的Spring Boot專案包含了必要的依賴。可以在pom.xml
中新增如下依賴:
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> <version>3.0.3</version> <!-- 使用合適的版本 --> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2020.0.3</version> <!-- 使用合適的版本 --> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
步驟2: 建立前置過濾器
建立一個檢查API金鑰的前置過濾器。如果API金鑰無效,我們將阻止請求繼續處理。
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.http.server.reactive.ServerHttpRequest; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; public class ApiKeyFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); // 驗證API金鑰 String apiKey = request.getHeaders().getFirst("API-Key"); if (apiKey == null || !apiKey.equals("正確的金鑰")) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); // 中斷請求 } return chain.filter(exchange); // 繼續處理請求 } @Override public int getOrder() { return -100; // 優先順序高 } }
步驟3: 建立後置過濾器
新增一個後置過濾器來在每個響應中新增自定義HTTP頭。
import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; public class AddResponseHeaderFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange).then(Mono.fromRunnable(() -> { exchange.getResponse().getHeaders().add("X-Service-Name", "MyService"); })); } @Override public int getOrder() { return 1000; // 優先順序低 } }
步驟4: 配置過濾器
在你的Spring Boot應用中配置這些過濾器。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class GatewayConfig { @Bean public ApiKeyFilter apiKeyFilter() { return new ApiKeyFilter(); } @Bean public AddResponseHeaderFilter addResponseHeaderFilter() { return new AddResponseHeaderFilter(); } }
總結
這個示例建立了兩個過濾器:一個用於在請求時檢查API金鑰的有效性,另一個用於在所有響應中新增自定義頭。透過這種方式,你可以在Spring Cloud Gateway中靈活地處理請求和響應,實現多樣化的路由邏輯和安全需求。