編寫自定義謂詞和過濾器

Spring Cloud Gateway Server MVC 使用 Spring WebMvc.fn API(javadoc)作為 API Gateway 功能的基礎。

Spring Cloud Gateway Server MVC 可使用這些 API 進行擴充套件。使用者通常希望編寫 RequestPredicateHandlerFilterFunction 的自定義實現,以及 HandlerFilterFunction 的兩種變體,一種用於“之前”過濾器,另一種用於“之後”過濾器。

基礎

Spring WebMvc.fn API 的最基本介面是 ServerRequestjavadoc)和 ServerResponsejavadoc)。它們提供了對 HTTP 請求和響應所有部分的訪問。

Spring WebMvc.fn 文件宣告“`ServerRequest` 和 ServerResponse 是不可變介面。在某些情況下,Spring Cloud Gateway Server MVC 必須提供替代實現,以便某些內容可以實現可變性,以滿足 API 閘道器的代理要求。

實現 RequestPredicate

Spring WebMvc.fn RouterFunctions.Builder 需要一個 RequestPredicatejavadoc)來匹配給定的 路由RequestPredicate 是一個函式式介面,因此可以用 lambda 實現。要實現的方法簽名是

boolean test(ServerRequest request)

RequestPredicate 示例實現

在此示例中,我們將展示一個謂詞的實現,用於測試特定 HTTP 頭是否是 HTTP 請求的一部分。

Spring WebMvc.fn 中的 RequestPredicatesGatewayRequestPredicates 中的 RequestPredicate 實現都作為 static 方法實現。我們將在此處執行相同的操作。

SampleRequestPredicates.java
import org.springframework.web.servlet.function.RequestPredicate;

class SampleRequestPredicates {
    public static RequestPredicate headerExists(String header) {
		return request -> request.headers().asHttpHeaders().containsKey(header);
    }
}

該實現是一個簡單的 lambda,它將 ServerRequest.Headers 物件轉換為更豐富的 HttpHeaders API。這允許謂詞測試命名 header 的存在。

如何使用自定義 RequestPredicate

要使用我們新的 headerExists RequestPredicate,我們需要將其插入到 RouterFunctions.Builder 上的適當方法中,例如 route()。當然,headerExists 方法中的 lambda 可以在下面的示例中內聯編寫。

RouteConfiguration.java
import static SampleRequestPredicates.headerExists;
import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> headerExistsRoute() {
        return route("header_exists_route")
            .route(headerExists("X-Green"), http())
            .before(uri("https://example.org"))
            .build();
    }
}

當 HTTP 請求具有名為 X-Green 的頭時,上述路由將被匹配。

編寫自定義 HandlerFilterFunction 實現

RouterFunctions.Builder 有三個選項可以新增過濾器:filterbeforeafterbeforeafter 方法是通用 filter 方法的特殊化。

實現 HandlerFilterFunction

filter 方法接受一個 HandlerFilterFunction 作為引數。HandlerFilterFunction<T extends ServerResponse, R extends ServerResponse> 是一個函式式介面,因此可以用 lambda 實現。要實現的方法簽名是

R filter(ServerRequest request, HandlerFunction<T> next)

這允許訪問 ServerRequest,並在呼叫 next.handle(request) 後訪問 ServerResponse

HandlerFilterFunction 示例實現

此示例將展示向請求和響應都新增一個頭。

SampleHandlerFilterFunctions.java
import org.springframework.web.servlet.function.HandlerFilterFunction;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;

class SampleHandlerFilterFunctions {
	public static HandlerFilterFunction<ServerResponse, ServerResponse> instrument(String requestHeader, String responseHeader) {
		return (request, next) -> {
			ServerRequest modified = ServerRequest.from(request).header(requestHeader, generateId()).build();
			ServerResponse response = next.handle(modified);
			response.headers().add(responseHeader, generateId());
			return response;
		};
	}
}

首先,從現有請求建立一個新的 ServerRequest。這允許我們使用 header() 方法新增頭。然後我們呼叫 next.handle() 並傳入修改後的 ServerRequest。然後使用返回的 ServerResponse 向響應新增頭。

如何使用自定義 HandlerFilterFunction 實現

RouteConfiguration.java
import static SampleHandlerFilterFunctions.instrument;
import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> instrumentRoute() {
		return route("instrument_route")
                .GET("/**", http())
				.filter(instrument("X-Request-Id", "X-Response-Id"))
                .before(uri("https://example.org"))
                .build();
    }
}

上述路由將向請求新增 X-Request-Id 頭,並向響應新增 X-Response-Id 頭。

編寫自定義 Before 過濾器實現

before 方法接受一個 Function<ServerRequest, ServerRequest> 作為引數。這允許建立具有更新資料的新 ServerRequest 以從函式返回。

Before 函式可以透過 HandlerFilterFunction.ofRequestProcessor() 適配為 HandlerFilterFunction 例項。

Before 過濾器示例實現

在此示例中,我們將向請求新增一個具有生成值的頭。

SampleBeforeFilterFunctions.java
import java.util.function.Function;
import org.springframework.web.servlet.function.ServerRequest;

class SampleBeforeFilterFunctions {
	public static Function<ServerRequest, ServerRequest> instrument(String header) {
		return request -> ServerRequest.from(request).header(header, generateId()).build();
	}
}

從現有請求建立一個新的 ServerRequest。這允許我們使用 header() 方法新增頭。此實現比 HandlerFilterFunction 簡單,因為我們只處理 ServerRequest

如何使用自定義 Before 過濾器實現

RouteConfiguration.java
import static SampleBeforeFilterFunctions.instrument;
import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> instrumentRoute() {
        return route("instrument_route").GET("/**", http())
            .before(uri("https://example.org"))
            .before(instrument("X-Request-Id"))
            .build();
    }
}

上述路由將向請求新增 X-Request-Id 頭。請注意使用 before() 方法,而不是 filter()

編寫自定義 After 過濾器實現

after 方法接受一個 BiFunction<ServerRequest,ServerResponse,ServerResponse>。這允許訪問 ServerRequestServerResponse,並且能夠返回一個帶有更新資訊的新 ServerResponse

After 函式可以透過 HandlerFilterFunction.ofResponseProcessor() 適配為 HandlerFilterFunction 例項。

After 過濾器示例實現

在此示例中,我們將向響應新增一個具有生成值的頭。

SampleAfterFilterFunctions.java
import java.util.function.BiFunction;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;

class SampleAfterFilterFunctions {
	public static BiFunction<ServerRequest, ServerResponse, ServerResponse> instrument(String header) {
		return (request, response) -> {
			response.headers().add(header, generateId());
			return response;
		};
	}
}

在這種情況下,我們只是將頭新增到響應並返回它。

如何使用自定義 After 過濾器實現

RouteConfiguration.java
import static SampleAfterFilterFunctions.instrument;
import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> instrumentRoute() {
        return route("instrument_route")
            .GET("/**", http())
            .before(uri("https://example.org"))
            .after(instrument("X-Response-Id"))
            .build();
    }
}

上述路由將向響應新增 X-Response-Id 頭。請注意使用 after() 方法,而不是 filter()

如何註冊自定義謂詞和過濾器以進行配置

要在外部配置中使用自定義謂詞和過濾器,您需要建立一個特殊的 Supplier 類並將其註冊為應用程式上下文中的 bean。

註冊自定義謂詞

要註冊自定義謂詞,您需要實現 PredicateSupplierPredicateDiscoverer 查詢返回 RequestPredicates 的靜態方法以進行註冊。

SampleFilterSupplier.java

import org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier;

class SamplePredicateSupplier implements PredicateSupplier {

	@Override
	public Collection<Method> get() {
		return Arrays.asList(SampleRequestPredicates.class.getMethods());
	}

}

要註冊 PredicateSupplier 以便在配置檔案中使用,您需要將該類新增為 bean,如以下示例所示

PredicateConfiguration.java
@Configuration
class PredicateConfiguration {

    @Bean
    public SamplePredicateSupplier samplePredicateSupplier() {
        return new SamplePredicateSupplier();
    }
}

將類新增到 META-INF/spring.factories 的要求已棄用,並將在下一個主要版本中刪除。

META-INF/spring.factories
org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier=\
  com.example.SamplePredicateSupplier

註冊自定義過濾器

SimpleFilterSupplier 允許輕鬆註冊自定義過濾器。FilterDiscoverer 查詢返回 HandlerFilterFunction 的靜態方法以進行註冊。如果您需要比 SimpleFilterSupplier 更大的靈活性,可以直接實現 FilterSupplier

SampleFilterSupplier.java
import org.springframework.cloud.gateway.server.mvc.filter.SimpleFilterSupplier;

class SampleFilterSupplier extends SimpleFilterSupplier {

    public SampleFilterSupplier() {
		super(SampleAfterFilterFunctions.class);
	}
}

要註冊 FilterSupplier 以便在配置檔案中使用,您需要將該類新增為 bean,如以下示例所示

FilterConfiguration.java
@Configuration
class FilterConfiguration {

    @Bean
    public SampleFilterSupplier sampleFilterSupplier() {
        return new SampleFilterSupplier();
    }
}

將類新增到 META-INF/spring.factories 的要求已棄用,並將在下一個主要版本中刪除。

META-INF/spring.factories
org.springframework.cloud.gateway.server.mvc.filter.FilterSupplier=\
  com.example.SampleFilterSupplier
© . This site is unofficial and not affiliated with VMware.