web-dev-qa-db-ja.com

SpringWebfluxでリクエスト本文を読み取る方法

私はSpring5、Netty、Springwebfluxを使用してAPIGatewayを開発しています。リクエストをゲートウェイで停止したい場合もありますが、リクエストの本文を読み取ってログに記録し、クライアントにエラーを返したい場合もあります。

私は本文にサブスクライブすることにより、WebFilterでこれを実行しようとしています。

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    if (enabled) {
        logger.debug("gateway is enabled. The Request is routed.");
        return chain.filter(exchange);
    } else {
        logger.debug("gateway is disabled. A 404 error is returned.");

        exchange.getRequest().getBody().subscribe();
        exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
        return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().allocateBuffer(0)));
    }
}

私がこれをするとき、それは体の内容が小さいときに働きます。しかし、私が大きなボビーを持っているとき、フラックスの最初の要素だけが読み取られるので、私は全身を持つことができません。これを行う方法はありますか?

4
user9349304

ここでの問題は、フィルター内で手動でサブスクライブしていることです。つまり、パイプラインの残りの部分から要求の読み取りを切断しています。 subscribe()を呼び出すと、基になるDisposableの管理に役立つSubscriptionが得られます。

したがって、次のように、プロセス全体を単一のパイプラインとして接続する必要があります。

Flux<DataBuffer> requestBody = exchange.getRequest().getBody();
// decode the request body as a Mono or a Flux
Mono<String> decodedBody = decodeBody(requestBody); 
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
return decodedBody.doOnNext(s -> logger.info(s))
                  .then(exchange.getResponse().setComplete());

リクエスト本文全体をMonoとしてデコードすると、ゲートウェイはリクエスト本文全体をメモリにバッファリングする必要があることに注意してください。

DataBufferは、意図的に低レベルのタイプです。それを文字列としてデコードする(つまり、サンプルのdecodeBodymethodを実装する)場合は、DecoderのようなSpringのさまざまなStringDecoder実装の1つを使用できます。

これはかなり大きくて複雑なスペースであるため、 Spring Cloud Gateway を使用したり、確認したりできます。これは、まさにそれ以上のことを行います。

5
Brian Clozel

1.投稿ルートに "readBody()"を追加します。

builder.routes()
.route("get_route", r -> r.path("/**")
    .and().method("GET")
    .filters(f -> f.filter(myFilter))
    .uri(myUrl))
.route("post_route", r -> r.path("/**")
    .and().method("POST")
    .and().readBody(String.class, requestBody -> {return true;})
    .filters(f -> f.filter(myFilter))
    .uri(myUrl))

2.次に、フィルターで本文の文字列を取得できます。

String body = exchange.getAttribute("cachedRequestBodyObject");

利点:

  1. ブロッキングなし。

  2. さらなるプロセスのために体を補充する必要はありません。

Spring Boot 2.0.6.RELEASE + Sring Cloud Finchley.SR2 + Spring CloudGatewayで動作します。

3
benaonreg