ブロック()/ blockFirst()/ blockLast()交換後bodyToMonoを呼び出すとき)(エラーを遮断しています

DaithiG:

私は、しかし、別の場所に生成されたファイルをストリーミングするWebfluxを使用しようとしています場合、エラーにファイルRANの世代、APIリターンの成功が、ファイルの代わりに、ファイル自体の生成中にエラーを詳述DTOと。ポストの使用およびAPIの設計を言い訳してくださいので、これは非常に古いと設計が不十分なAPIを使用しています。

APIコール(エクスチェンジ())からの応答がClientResponseです。ここから、私はどちらかのファイルを作成中にエラーが発生した場合、ファイルにストリーム、またはすることができbodyToMonoを使用してByteArrayResourceに変換することができ、その後、私はまたbodyToMonoを使用してDTOに変換することができます。しかし、私はどちらかまたはClientResponseのヘッダの内容に応じて行うように見えることはできません。

実行時に私はによって引き起こさIllegalStateExceptionが取得します

ブロック()/ blockFirst()/ blockLast()スレッドリアクター-HTTPクライアント・ファイルディスクリプタ-12でサポートされていない、ブロックされています

私は私の問題は、私は同じ関数チェーンで2回)(ブロックを呼び出すことはできませんということだと思います。

私のコードスニペットはそうのようなものです:

webClient.post()
        .uri(uriBuilder -> uriBuilder.path("/file/")
                                      .queryParams(params).build())
        .exchange()
        .doOnSuccess(cr -> {
                if (MediaType.APPLICATION_JSON_UTF8.equals(cr.headers().contentType().get())) {
                    NoPayloadResponseDto dto = cr.bodyToMono(NoPayloadResponseDto.class).block();
                    createErrorFile(dto);
                }
                else {
                    ByteArrayResource bAr = cr.bodyToMono(ByteArrayResource.class).block();
                    createSpreadsheet(bAr);
                }
            }
        )
        .block();

基本的に私は、異なるヘッダで定義されているのMediaTypeに基づいてClientResponseを処理したいです。

これは可能ですか?

ブライアンClozel:

まず、あなたがこのユースケースを解決するコードスニペットを理解するのに役立ちますいくつかのこと。

  1. あなたは反応型を返すメソッド内でブロックするメソッドを呼び出してはなりません。あなたは、あなたのアプリケーションのいくつかのスレッドの1をブロックします、それはアプリケーションのための非常に悪いです
  2. とにかく原子炉3.2のように、反応性パイプライン内のブロッキングすると、エラーがスローされます
  3. 呼び出しsubscribeのコメントで提案されているように、どちらか良いアイデアではありません。これは、多かれ少なかれ、別のスレッドでタスクとしてそのジョブを開始するようなものです。それは完了だときは、(コールバックを買ってあげるsubscribe方法はラムダを与えることができます)が、あなたはそのタスクを使用して、現在のパイプラインを切り離すことにしています。この場合、クライアントのHTTPレスポンスを閉じて、ファイルに書き込み、完全なレスポンスボディを読み込むための機会を得る前に洗浄することができ、リソース
  4. あなたがメモリに全体の応答をバッファリングしたくない場合は、春は提供DataBuffer(プールすることができByteBufferのインスタンスを考えます)。
  5. あなたが実装しようとしている方法は、それ自体が(戻ってブロックしている場合は、ブロックを呼び出すことができvoid、テストケースには、たとえば、たとえば)。

ここでは、これを行うために使用することができるとコードスニペットです:

Mono<Void> fileWritten = WebClient.create().post()
        .uri(uriBuilder -> uriBuilder.path("/file/").build())
        .exchange()
        .flatMap(response -> {
            if (MediaType.APPLICATION_JSON_UTF8.equals(response.headers().contentType().get())) {
                Mono<NoPayloadResponseDto> dto = response.bodyToMono(NoPayloadResponseDto.class);
                return createErrorFile(dto);
            }
            else {
                Flux<DataBuffer> body = response.bodyToFlux(DataBuffer.class);
                return createSpreadsheet(body);
            }
        });
// Once you get that Mono, you should give plug it into an existing
// reactive pipeline, or call block on it, depending on the situation

あなたが見ることができるように、我々は、I / Oを扱うどこでも、方法をブロックしていない戻ってきているMono<Void>の反応性等価物である、done(error)エラーが起こった場合は、物事が行われている信号をそのコールバック。

私は確信して何じゃないので、createErrorFileこの方法がすべき、私はのためのサンプル提供してきましたcreateSpreadsheetそれは単にファイルに身体のバイトを書き込みます。databuffersがリサイクルされる可能性があります/プールされたことから、我々は我々が終わったら、それらを解放する必要があることに注意してください。

private Mono<Void> createSpreadsheet(Flux<DataBuffer> body) {
    try {
        Path file = //...
        WritableByteChannel channel = Files.newByteChannel(file, StandardOpenOption.WRITE);
        return DataBufferUtils.write(body, channel).map(DataBufferUtils::release).then();
    } catch (IOException exc) {
        return Mono.error(exc);
    }
}

この実装では、あなたのアプリケーションがいくつか開催しますDataBuffer(反応性オペレーターはパフォーマンス上の理由から、値をプリフェッチしている)与えられた時にメモリ内のインスタンスを、彼らは反応性形で来るようバイト書き込みます。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=171965&siteId=1