2017-12-31 268 views
3

私は中間記憶装置なしで圧縮された(GZIP)ストリームを読み書きする必要があります。現在、私は執筆のためにSpring RestTemplateを使用していますが、Apache HTTPクライアントは読み込みを行います(大きなストリームの読み込みにRestTemplateを使用できない理由については、私の答えhereを参照してください)。実装はかなり簡単です。ここでを応答InputStreamで叩いて移動します。Flux <DataBuffer>を解凍するにはどうすればいいですか?

今、私はSpring 5 WebClient(現状のファンではないから)を使用するように変更したいと思います。しかしながら、WebClientは性質上反応性であり、Flux<Stuff>を扱う。私はFlux<DataBuffer>を得ることができると信じています。ここでDataBufferByteBufferを超える抽象です。質問は、フルストリームをメモリに保存することなく、即座に解凍する方法です(OutOfMemoryError、私はあなたを見ています)、またはローカルディスクに書き込むことですか?フードの下でWebClientがNettyを使用することに言及する価値があります。

  • リアクタネーティブissue-251も参照してください。
  • Springインテグレーションissue-2300に関連すると、

私は自分の研究をしましたが、オンラインで入手できる資料は特に役に立ちませんでした。

compression on java nio direct buffers

Writing GZIP file with nio

Reading a GZIP file from a FileChannel (Java NIO)

(de)compressing files using NIO

Iterable gzip deflate/inflate in Java

+0

データバッファ上で 'asInputStream()'メソッドを使って、 'GZIPInputStream'に入れないだけですか? – vandale

+0

@vandale私はそれに従わない、各 'DataBuffer'は部分だけです、そうですか? 'GZIPInputStream'は完全な' InputStream'で動作するはずです。 'DataBuffer.asInputStream'と' SequenceInputStream'を使って 'InputStream'を再構築する方法がありますが、それは反応的なNIOを使う目的を破るでしょう。 –

答えて

1
public class HttpResponseHeadersHandler extends ChannelInboundHandlerAdapter { 
    private final HttpHeaders httpHeaders; 

    @Override 
    public void channelRead(ChannelHandlerContext ctx, Object msg) { 
     if (msg instanceof HttpResponse && 
       !HttpStatus.resolve(((HttpResponse) msg).status().code()).is1xxInformational()) { 
      HttpHeaders headers = ((HttpResponse) msg).headers(); 

      httpHeaders.forEach(e -> { 
       log.warn("Modifying {} from: {} to: {}.", e.getKey(), headers.get(e.getKey()), e.getValue()); 
       headers.set(e.getKey(), e.getValue()); 
      }); 
     } 
     ctx.fireChannelRead(msg); 
    } 
} 

それから私はを作成ハンドラを追加WebClientとし、afterNettyContextInitで使用する:

ctx.addHandlerLast(new ReadTimeoutHandler(readTimeoutMillis, TimeUnit.MILLISECONDS)); 
ctx.addHandlerLast(new Slf4JLoggingHandler()); 
if (forceDecompression) { 
    io.netty.handler.codec.http.HttpHeaders httpHeaders = new ReadOnlyHttpHeaders(
      true, 
      CONTENT_ENCODING, GZIP, 
      CONTENT_TYPE, APPLICATION_JSON 
    ); 
    HttpResponseHeadersHandler headersModifier = new HttpResponseHeadersHandler(httpHeaders); 
    ctx.addHandlerFirst(headersModifier); 
} 
ctx.addHandlerLast(new HttpContentDecompressor()); 

これを、当然のことながら、GZIP圧縮されていない応答のために失敗するので、私は唯一、I特定のユースケースのためにWebClientのこのインスタンスを使用します応答が圧縮されていることを確認してください。

書き込みは簡単です:春はResourceEncoderなので、InputStreamInputStreamResourceに簡単に変換できます。

関連する問題