istio 或 spring webflux 处理 header "Content-Encoding: deflate" 中是否有任何内置过滤器来解压缩请求 body

is there any built in filter in istio or in spring webflux handling header "Content-Encoding: deflate" to decompress the request body

我在 spring 云函数 webflux 上有一个微服务 运行,需要处理作为 http 请求发送的压缩数据 body

是否有任何 spring 内置的网络过滤器或配置来处理数据的解压缩

$ echo '{ "key":"hello" }' > body
$ curl -X POST -H "Content-Type: application/json" --data-binary @body http://localhost:8080 # prints 'hello'
$ echo '{ "key":"hello" }' | deflate > body.dat
$ curl -X POST -H "Content-Type: application/json" -H "Content-Encoding: deflate" --data-binary @body.dat http://localhost:8080 # fails

这可以在 istio envoy 过滤器中处理吗?

import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebExchangeDecorator;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.InputStream;
import java.util.List;
import java.util.zip.InflaterInputStream;

public class GzipFilter implements WebFilter {

    private static final String ENCODING_VALUE = "deflate";

    /**
     * Process the Web request and (optionally) delegate to the next
     * {@code WebFilter} through the given {@link WebFilterChain}.
     *
     * @param exchange the current server exchange
     * @param chain    provides a way to delegate to the next filter
     * @return {@code Mono<Void>} to indicate when request processing is complete
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        List<String> strings = exchange.getRequest().getHeaders().get(HttpHeaders.CONTENT_ENCODING);
        if (strings != null && strings.contains(ENCODING_VALUE)) {
            return chain.filter(new GzippedInputStreamWrapper(exchange));
        } else {
            return chain.filter(exchange);
        }
    }
}

public final class GzippedInputStreamWrapper extends ServerWebExchangeDecorator {


    private final ServerHttpRequestDecorator requestDecorator;


    protected GzippedInputStreamWrapper(ServerWebExchange delegate) {
        super(delegate);
        this.requestDecorator = new GzipRequestDecorator(delegate.getRequest());
    }

    @Override
    public ServerHttpRequest getRequest() {
        return this.requestDecorator;
    }
}

public class GzipRequestDecorator extends ServerHttpRequestDecorator {

    private final DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();

    public GzipRequestDecorator(ServerHttpRequest delegate) {
        super(delegate);
    }

    @Override
    public Flux<DataBuffer> getBody() {
        return super.getBody().flatMap(dataBuffer -> {
            try {
                final InputStream gzipInputStream = new InflaterInputStream(dataBuffer.asInputStream());
                return DataBufferUtils.readInputStream(() -> gzipInputStream, this.dataBufferFactory, gzipInputStream.available());
            } catch (Exception e) {
                return Flux.error(e);
            }
        });
    }
}

定义 webfilter GzipFilter 拦截指定 header 的每个请求和进程。 GzipRequestDecorator 进行 body 内容膨胀并将其发送到下游处理函数的转换