切換語言為:簡體

SpringBoot Gateway的前置過濾器和後置過濾器

  • 爱糖宝
  • 2024-07-25
  • 2082
  • 0
  • 0

Spring Cloud Gateway 基於WebFlux框架使用非阻塞API。它主要透過路由定義來決定請求如何被處理。每個路由可以指定一個或多個過濾器,這些過濾器可以修改請求和響應。

  • 前置過濾器:這些過濾器在請求實際被路由到下游服務之前執行。它們可以用來修改請求頭、查詢引數、驗證請求等。

  • 後置過濾器:這些過濾器在請求被下游服務處理之後執行,通常用於修改響應或進行日誌記錄。

簡單概念

過濾器工作流程

在Spring Cloud Gateway中,請求經過以下幾個步驟:

  1. 請求匹配:判斷請求是否匹配某個路由的條件。

  2. 前置過濾器執行:執行所有前置過濾器,可能修改請求。

  3. 請求路由:將請求轉發到相應的下游服務。

  4. 後置過濾器執行:在得到下游服務響應後執行,可能修改響應。

原始碼解析

我們將看看關鍵的類和介面:

  • 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中靈活地處理請求和響應,實現多樣化的路由邏輯和安全需求。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.