How to gzip HTTP request, created by org.springframework.web.client.RestTemplate?
I am using Spring 4.2.6
with Spring Boot 1.3.5
(Java SE, not Android or Javascript in the web browser).
I am making some really big POST
requests, and I want request body to be compressed.
The main idea is to create
requestCallback
, which will copy data you want to send fromgzipOutputStream
directly torequest
stream.Now you can use it in the next way:
Links:
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.Where
interceptor
could be:getGzip
I copiedAfter configuring the interceptor all requests will be zipped.
The disadvantage of this approach is that it does not support streaming as the
ClientHttpRequestInterceptor
receives the content as abyte[]
If you require streaming create a custom
ClientHttpRequestFactory
, sayGZipClientHttpRequestFactory
, and use it like this:Where
GZipClientHttpRequestFactory
is:And
ZippedClientHttpRequest
is:And finally
WrapperClientHttpRequest
is:This approach creates a request with chunked transfer encoding, this can be changed setting the content length header, if size is known.
The advantage of the
ClientHttpRequestInterceptor
and/or customClientHttpRequestFactory
approach is that it works with any method of RestTemplate. An alternate approach, passing a RequestCallback is possible only withexecute
methods, this because the other methods of RestTemplate internally create their own RequestCallback(s) that produce the content.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.
Further to the above answer from @TestoTestini, if we take advantage of Java 7+'s 'try-with-resources' syntax since both
ByteArrayOutputStream
andGZIPOutputStream
implement closeable(), we can shrink the getGzip function into the following:(I couldn't find a way of commenting on @TestoTestini's original answer and retaining the above code format, hence this Answer).