AdaptCachedBody フィルター

AdaptCachedBody フィルターは、以前にキャッシュされたリクエストボディを、下流のフィルターおよびプロキシ経由のルートが再読み取りできるようにします。

サーブレット環境では、HttpServletRequest 入力ストリームは一度しか読み取ることができません。ビフォアフィルターがリクエストボディをインスペクションまたは変換する必要があり(たとえば、HMAC 署名を計算する場合)、かつ同じボディがダウンストリームサービスにも渡される必要がある場合は、まずボディをキャッシュする必要があります。

これは 2 つのステップで行われます。

  1. MvcUtils.cacheAndReadBody(request, BodyType.class) を使用してボディを読み込み、キャッシュします。

  2. リクエストをラップして、後続の読み取りでキャッシュされたバイトが返されるようにします。

このフィルターは、JavaDSL を使用してのみ構成できます。

次の例では、カスタムの before フィルター内で生のリクエストボディを String として読み込み、その後 adaptCachedBody を使用してボディがダウンストリームサービスにも転送されるようにしています。

RouteConfiguration.java
import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.adaptCachedBody;
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> gatewayRouterFunctionsCachedBody() {
        return route("cached_body_route")
            .route(path("/api/**"), http())
            .before(uri("https://example.org"))
            .before(request -> {
                // Read the body and store it in the request attributes.
                // Subsequent calls to request.body() or servletRequest().getInputStream()
                // will see the cached bytes.
                Optional<String> body = MvcUtils.cacheAndReadBody(request, String.class); (1)
                body.ifPresent(b -> {
                    // e.g. validate an HMAC, log, or transform
                });
                return request;
            })
            .before(adaptCachedBody())   (2)
            .build();
    }
}
1cacheAndReadBody は元の InputStream を消費し、バイト列をリクエスト属性として保存します。逆直列化されたボディが返され、その後の cacheAndReadBody 呼び出しでは、ストリームを再読み込みすることなくキャッシュされたバイト列が返されます。
2adaptCachedBody は、キャッシュされたバイト列を裏付けとした HttpServletRequestWrapper でリクエストをラップするため、ダウンストリームサービス(および後続のフィルター)は、getInputStream() からボディを、まるで一度も消費されたことがないかのように読み取ることができます。

adaptCachedBody は、cacheAndReadBody が呼び出された後に登録する必要があります。ボディがキャッシュされる前(つまり、CACHED_REQUEST_BODY_ATTR にキャッシュされたバイトが存在しない場合)に登録された場合、フィルターは何もせず、ダウンストリームサービスは空のボディを受け取ります。