如何在spring reactive中解压压缩内容?

m1m5dgzv  于 2023-01-16  发布在  Spring
关注(0)|答案(2)|浏览(93)

在将我的spring服务器从servlet迁移到reactive时,我不得不将代码中的所有过滤器都改为WebFilter,其中一个过滤器是解压缩压缩的内容,但我不能用新的WebFilter做同样的事情。
使用servlet时,我用GzipInputStream Package 了输入流。使用springreactive的最佳实践是什么?

vohkndzv

vohkndzv1#

解决方案:

@Component
public class GzipFilter implements WebFilter {

  private static final Logger LOG = LoggerFactory.getLogger(GzipFilter.class);
  public static final String CONTENT_ENCODING = "content-encoding";
  public static final String GZIP = "gzip";
  public static final String UTF_8 = "UTF-8";

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {

    ServerHttpRequest request = exchange.getRequest();

    if (!isGzip(request)) {
      return chain.filter(exchange);
    }
    else {

      ServerHttpRequest mutatedRequest = new ServerHttpRequestWrapper(request);
      ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();

      return chain.filter(mutatedExchange);
    }
  }

  private boolean isGzip(ServerHttpRequest serverHttpRequest) {
    String encoding = serverHttpRequest.getHeaders().getFirst(CONTENT_ENCODING);

    return encoding != null && encoding.contains(GZIP);
  }

  private static class ServerHttpRequestWrapper implements ServerHttpRequest {

    private ServerHttpRequest request;

    public ServerHttpRequestWrapper(ServerHttpRequest request) {
      this.request = request;
    }

    private static byte[] getDeflatedBytes(GZIPInputStream gzipInputStream) throws IOException {
      StringWriter writer = new StringWriter();
      IOUtils.copy(gzipInputStream, writer, UTF_8);
      return writer.toString().getBytes();
    }

    @Override
    public String getId() {
      return request.getId();
    }

    @Override
    public RequestPath getPath() {
      return request.getPath();
    }

    @Override
    public MultiValueMap<String, String> getQueryParams() {
      return request.getQueryParams();
    }

    @Override
    public MultiValueMap<String, HttpCookie> getCookies() {
      return request.getCookies();
    }

    @Override
    public String getMethodValue() {
      return request.getMethodValue();
    }

    @Override
    public URI getURI() {
      return request.getURI();
    }

    @Override
    public Flux<DataBuffer> getBody() {

      Mono<DataBuffer> mono = request.getBody()
          .map(dataBuffer -> dataBuffer.asInputStream(true))
          .reduce(SequenceInputStream::new)
          .map(inputStream -> {
            try (GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream)) {
              byte[] targetArray = getDeflatedBytes(gzipInputStream);
              return new DefaultDataBufferFactory().wrap(targetArray);
            }
            catch (IOException e) {
              throw new IllegalGzipRequest(String.format("failed to decompress gzip content. Path: %s", request.getPath()));
            }
          });

      return mono.flux();
    }

    @Override
    public HttpHeaders getHeaders() {
      return request.getHeaders();
    }
  }

}
o0lyfsai

o0lyfsai2#

爱@Yuval的解决方案!
我最初的想法是将Flux转换为本地文件,然后解压缩本地文件。
但是在Spring Reactive中下载一个文件太有挑战性了。我在Google上搜索了很多,大多数都阻止了获取文件的方式,(eidogg. Spring WebClient: How to stream large byte[] to file?How to correctly read Flux and convert it to a single inputStream,它们都不起作用...)这没有意义,在React流中调用block()时会抛出错误。
@Yuval拯救了我的一天!对我来说效果很好!

相关问题