如何使用Spring RestTemplate压缩压缩HTTP请求?

Bar*_*cki 12 java spring http http-compression

如何gzip 创建的HTTP 请求org.springframework.web.client.RestTemplate?

我正在使用Spring 4.2.6Spring Boot 1.3.5(Java SE,而不是Android或Javascript在Web浏览器中).

我正在做一些非常大的POST请求,我希望压缩请求体.

Tes*_*ini 12

我提出了两个解决方案,一个更简单,没有流,一个支持流.

如果您不需要流式传输,请使用自定义ClientHttpRequestInterceptorSpring功能.

RestTemplate rt = new RestTemplate();
rt.setInterceptors(Collections.singletonList(interceptor));
Run Code Online (Sandbox Code Playgroud)

哪里interceptor可能是:

ClientHttpRequestInterceptor interceptor = new ClientHttpRequestInterceptor() {

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {
        request.getHeaders().add("Content-Encoding", "gzip");
        byte[] gzipped = getGzip(body);
        return execution.execute(request, gzipped);
    } 
 }
Run Code Online (Sandbox Code Playgroud)

getGzip复制了

    private byte[] getGzip(byte[] body) throws IOException {

        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        try {
            GZIPOutputStream zipStream = new GZIPOutputStream(byteStream);
            try {
                zipStream.write(body);
            } finally {
                zipStream.close();
            }
        } finally {
            byteStream.close();
        }

        byte[] compressedData = byteStream.toByteArray();
        return compressedData;

    }
Run Code Online (Sandbox Code Playgroud)

配置拦截器后,所有请求都将被压缩.

这种方法的缺点是它不支持流式传输,因为ClientHttpRequestInterceptor接收内容为byte[]

如果你需要流式传输创建一个自定义ClientHttpRequestFactory,比如说GZipClientHttpRequestFactory,并像这样使用它:

    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    requestFactory.setBufferRequestBody(false);
    ClientHttpRequestFactory gzipRequestFactory = new GZipClientHttpRequestFactory(requestFactory);
    RestTemplate rt = new RestTemplate(gzipRequestFactory);
Run Code Online (Sandbox Code Playgroud)

在哪里GZipClientHttpRequestFactory:

public class GZipClientHttpRequestFactory extends AbstractClientHttpRequestFactoryWrapper {

    public GZipClientHttpRequestFactory(ClientHttpRequestFactory requestFactory) {
        super(requestFactory);
    }

    @Override
    protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory)
            throws IOException {
        ClientHttpRequest delegate = requestFactory.createRequest(uri, httpMethod);
        return new ZippedClientHttpRequest(delegate);
    }

}
Run Code Online (Sandbox Code Playgroud)

并且ZippedClientHttpRequest是:

public class ZippedClientHttpRequest extends WrapperClientHttpRequest
{
    private GZIPOutputStream zip;

    public ZippedClientHttpRequest(ClientHttpRequest delegate) {
        super(delegate);
        delegate.getHeaders().add("Content-Encoding", "gzip");
        // here or in getBody could add content-length to avoid chunking
        // but is it available ? 
        // delegate.getHeaders().add("Content-Length", "39");

    }

    @Override
    public OutputStream getBody() throws IOException {
        final OutputStream body = super.getBody();
        zip = new GZIPOutputStream(body);
        return zip;
    }

    @Override
    public ClientHttpResponse execute() throws IOException {
        if (zip!=null) zip.close();
        return super.execute();
    }

}
Run Code Online (Sandbox Code Playgroud)

最后WrapperClientHttpRequest是:

public class WrapperClientHttpRequest implements ClientHttpRequest {

    private final ClientHttpRequest delegate;

    protected WrapperClientHttpRequest(ClientHttpRequest delegate) {
        super();
        if (delegate==null)
            throw new IllegalArgumentException("null delegate");
        this.delegate = delegate;
    }

    protected final ClientHttpRequest getDelegate() {
        return delegate;
    }

    @Override
    public OutputStream getBody() throws IOException {
        return delegate.getBody();
    }

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

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

    @Override
    public HttpMethod getMethod() {
        return delegate.getMethod();
    }

    @Override
    public ClientHttpResponse execute() throws IOException {
        return delegate.execute();
    }
}
Run Code Online (Sandbox Code Playgroud)

此方法使用分块传输编码创建请求,如果已知大小,则可以更改设置内容长度标头.

ClientHttpRequestInterceptor和/或自定义ClientHttpRequestFactory方法的优点是它适用于RestTemplate的任何方法.另一种方法,传递一个RequestCallback能够仅与execute方法,这是因为RestTemplate的其它方法在内部创建他们自己的RequestCallback(S)产生的内容.

BTW似乎很少支持在服务器上解压缩gzip请求.还相关:在WebRequest中发送gzip压缩数据?这指向Zip Bomb问题.我想你必须为它编写一些代码.