カスタム述語とフィルターの作成
Spring Cloud Gateway サーバー MVC は、API ゲートウェイ機能の基礎として Spring WebMvc.fn API ( javadoc ) を使用します。
Spring Cloud Gateway サーバー MVC は、これらの API を使用して拡張できます。ユーザーは通常、RequestPredicate
(Javadoc) と HandlerFilterFunction
(Javadoc) のカスタム実装と、HandlerFilterFunction
の 2 つのバリエーション (「前」フィルター用と「後」フィルター用) を作成することを期待するかもしれません。
基礎
Spring WebMvc.fn API の一部である最も基本的なインターフェースは、ServerRequest
( javadoc ) および ServerResponse ( javadoc ) です。これらは、HTTP リクエストとレスポンスのすべての部分へのアクセスを提供します。
Spring WebMvc.fn ドキュメントでは、「 `ServerRequest` および ServerResponse は不変のインターフェースである」と宣言されています。場合によっては、API ゲートウェイのプロキシ要件を満たすために一部のものを変更できるように、Spring Cloud Gateway サーバー MVC は代替実装を提供する必要があります。 |
RequestPredicate の実装
Spring WebMvc.fn RouterFunctions.Builder (Javadoc) は、RequestPredicate
( javadoc ) が指定されたルートと一致することを期待します。RequestPredicate
は関数型インターフェースであるため、ラムダを使用して実装できます。実装するメソッドシグネチャーは次のとおりです。
boolean test(ServerRequest request)
RequestPredicate の実装例
この例では、特定の HTTP ヘッダーが HTTP リクエストの一部であることをテストするための述語の実装を示します。
Spring WebMvc.fn RequestPredicates
(Javadoc) および GatewayRequestPredicates [GitHub] (英語) の RequestPredicate
実装はすべて static
メソッドとして実装されます。ここでも同じことを行います。
import org.springframework.web.reactive.function.server.RequestPredicate;
class SampleRequestPredicates {
public static RequestPredicate headerExists(String header) {
return request -> request.headers().asHttpHeaders().containsKey(header);
}
}
実装は、ServerRequest.Headers (Javadoc) オブジェクトを HttpHeaders (Javadoc) のより豊富な API に変換する単純なラムダです。これにより、述語で名前付き header
の存在をテストできるようになります。
カスタム RequestPredicate の使用方法
新しい headerExists
RequestPredicate
を使用するには、それを route() (Javadoc) などの RouterFunctions.Builder
上の適切なメソッドに接続する必要があります。もちろん、headerExists
メソッドのラムダは、以下の例のようにインラインで記述することができます。
import static SampleRequestPredicates.headerExists;
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("https://example.org"))
.build();
}
}
上記のルートは、HTTP リクエストに X-Green
という名前のヘッダーがある場合に一致します。
カスタム HandlerFilterFunction 実装の作成
RouterFunctions.Builder
には、フィルターを追加するための 3 つのオプションがあります: filter (Javadoc) 、before (Javadoc) 、after (Javadoc) 。before
および after
メソッドは、一般的な filter
メソッドを特殊化したものです。
HandlerFilterFunction の実装
filter
メソッドは、パラメーターとして HandlerFilterFunction (Javadoc) を受け取ります。HandlerFilterFunction<T extends ServerResponse, R extends ServerResponse>
は関数型インターフェースであるため、ラムダを使用して実装できます。実装するメソッドシグネチャーは次のとおりです。
R filter(ServerRequest request, HandlerFunction<T> next)
これにより、ServerRequest
へのアクセスが可能になり、next.handle(request)
を呼び出した後、ServerResponse
へのアクセスが可能になります。
HandlerFilterFunction の実装例
この例では、リクエストとレスポンスの両方にヘッダーを追加する方法を示します。
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 実装の使用方法
import static SampleHandlerFilterFunctions.instrument;
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("https://example.org"))
.filter(instrument("X-Request-Id", "X-Response-Id"))
.build();
}
}
上記のルートは、リクエストに X-Request-Id
ヘッダーを追加し、レスポンスに X-Response-Id
ヘッダーを追加します。
フィルター実装前のカスタムの作成
before
メソッドは、パラメーターとして Function<ServerRequest, ServerRequest>
を受け取ります。これにより、関数から返される更新データを含む新しい ServerRequest
を作成できます。
Before 関数は、HandlerFilterFunction.ofRequestProcessor() (Javadoc) を介して HandlerFilterFunction インスタンスに適合させることができます。 |
フィルター実装前の例
この例では、生成された値を含むヘッダーをリクエストに追加します。
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()
メソッドを使用してヘッダーを追加できるようになります。ServerRequest
のみを扱うため、この実装は HandlerFilterFunction
よりも単純です。
カスタム Before フィルター実装の使用方法
import static SampleBeforeFilterFunctions.instrument;
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("https://example.org"))
.before(instrument("X-Request-Id"))
.build();
}
}
上記のルートでは、リクエストに X-Request-Id
ヘッダーが追加されます。filter()
ではなく before()
メソッドが使用されていることに注意してください。
フィルター実装後のカスタムの作成
after
メソッドは BiFunction<ServerRequest,ServerResponse,ServerResponse>
を受け取ります。これにより、ServerRequest
と ServerResponse
の両方にアクセスでき、更新された情報を含む新しい ServerResponse
を返すことができます。
After 関数は、HandlerFilterFunction.ofResponseProcessor() (Javadoc) を介して HandlerFilterFunction インスタンスに適合させることができます。 |
フィルター実装後の例
この例では、生成された値を含むヘッダーをレスポンスに追加します。
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 フィルター実装の使用方法
import static SampleAfterFilterFunctions.instrument;
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("https://example.org"))
.after(instrument("X-Response-Id"))
.build();
}
}
上記のルートでは、レスポンスに X-Response-Id
ヘッダーが追加されます。filter()
ではなく after()
メソッドが使用されていることに注意してください。
構成用のカスタム述語とフィルターを登録する方法
外部構成でカスタム述語とフィルターを使用するには、特別な Supplier クラスを作成し、それを META-INF/spring.factories
に登録する必要があります。
カスタム述語の登録
カスタム述語を登録するには、PredicateSupplier
を実装する必要があります。PredicateDiscoverer
は、登録する RequestPredicates
を返す静的メソッドを探します。
SampleFilterSupplier.java
import org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier;
@Configuration
class SamplePredicateSupplier implements PredicateSupplier {
@Override
public Collection<Method> get() {
return Arrays.asList(SampleRequestPredicates.class.getMethods());
}
}
次に、クラスを META-INF/spring.factories
に追加する必要があります。
org.springframework.cloud.gateway.server.mvc.predicate.PredicateSupplier=\
com.example.SamplePredicateSupplier
カスタムフィルターの登録
SimpleFilterSupplier
ではカスタムフィルターを簡単に登録できます。FilterDiscoverer
は、登録する HandlerFilterFunction
を返す静的メソッドを探します。SimpleFilterSupplier
よりも高い柔軟性が必要な場合は、FilterSupplier
を直接実装できます。
import org.springframework.cloud.gateway.server.mvc.filter.SimpleFilterSupplier;
@Configuration
class SampleFilterSupplier extends SimpleFilterSupplier {
public SampleFilterSupplier() {
super(SampleAfterFilterFunctions.class);
}
}
次に、クラスを META-INF/spring.factories
に追加する必要があります。
org.springframework.cloud.gateway.server.mvc.filter.FilterSupplier=\
com.example.SampleFilterSupplier