如何使用Spring RestTemplate压缩HTTP请求? [英] How to zip- compress HTTP request with Spring RestTemplate?

查看:155
本文介绍了如何使用Spring RestTemplate压缩HTTP请求?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何gzip通过org.springframework.web.client.RestTemplate?

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

I am using Spring 4.2.6 with Spring Boot 1.3.5 (Java SE, not Android or Javascript in the web browser).

我正在发出一些非常大的POST请求,并且我希望压缩请求正文.

I am making some really big POST requests, and I want request body to be compressed.

推荐答案

我提出了两种解决方案,一种更简单,无需流传输,而另一种支持流传输.

I propose two solutions, one simpler without streaming and one that supports streaming.

如果不需要流,请使用自定义

If you don't require streaming, use a custom ClientHttpRequestInterceptor, a Spring feature.

RestTemplate rt = new RestTemplate();
rt.setInterceptors(Collections.singletonList(interceptor));

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

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;

    }

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

After configuring the interceptor all requests will be zipped.

此方法的缺点是它不支持流传输,因为ClientHttpRequestInterceptorbyte[]

The disadvantage of this approach is that it does not support streaming as the ClientHttpRequestInterceptor receives the content as a byte[]

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

If you require streaming create a custom ClientHttpRequestFactory, say GZipClientHttpRequestFactory, and use it like this:

    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    requestFactory.setBufferRequestBody(false);
    ClientHttpRequestFactory gzipRequestFactory = new GZipClientHttpRequestFactory(requestFactory);
    RestTemplate rt = new RestTemplate(gzipRequestFactory);

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

}

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

}

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

此方法使用分块传输编码创建请求,可以通过设置内容长度来进行更改标头(如果知道大小).

This approach creates a request with chunked transfer encoding, this can be changed setting the content length header, if size is known.

ClientHttpRequestInterceptor和/或自定义ClientHttpRequestFactory方法的优点是,它可以与RestTemplate的任何方法一起使用.一种替代方法,传递 RequestCallback 仅可用于

The advantage of the ClientHttpRequestInterceptor and/or custom ClientHttpRequestFactory approach is that it works with any method of RestTemplate. An alternate approach, passing a RequestCallback is possible only with execute methods, this because the other methods of RestTemplate internally create their own RequestCallback(s) that produce the content.

顺便说一句,似乎有在服务器上解压缩gzip请求的基本支持.还相关:在WebRequest中发送压缩数据吗?指向 Zip Bomb 问题.我认为您必须为此编写一些代码.

BTW it seems that there is little support to decompress gzip request on the server. Also related: Sending gzipped data in WebRequest? that points to the Zip Bomb issue. I think you will have to write some code for it.

这篇关于如何使用Spring RestTemplate压缩HTTP请求?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆