1

在将我的 spring 服务器从 servlet 迁移到响应式时,我必须将代码中的所有过滤器更改为 WebFilter。其中一个过滤器是解压缩 gzip 压缩的内容,但我无法对新的 WebFilter 做同样的事情。

使用 servlet,我用 GzipInputStream 包装了输入流。使用弹簧反应的最佳实践是什么?

4

1 回答 1

0

解决方案:

@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();
    }
  }


}
于 2020-09-22T12:55:46.090 回答