Ответ 1
Я предлагаю два решения, один более простой без потоковой передачи и один, поддерживающий потоковое вещание.
Если не требуется потоковая передача, используйте ClientHttpRequestInterceptor
, Spring.
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;
}
После настройки перехватчика все запросы будут заархивированы.
Недостатком этого подхода является то, что он не поддерживает потоковое вещание, поскольку ClientHttpRequestInterceptor
получает контент как byte[]
Если требуется потоковая передача, создайте пользовательский ClientHttpRequestFactory
, скажем GZipClientHttpRequestFactory
и используйте его следующим образом:
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();
}
}
Этот подход создает запрос с chunked transfer encoding, это можно изменить, задав заголовок длины контента, если размер известен.
Преимущество подхода ClientHttpRequestInterceptor
и/или custom ClientHttpRequestFactory
заключается в том, что он работает с любым методом RestTemplate. Альтернативный подход, проходящий RequestCallback, возможен только с execute
, это потому, что другие методы RestTemplate внутренне создают свои собственные RequestCallback (ы), которые создают контент.
Кстати, кажется, что есть небольшая поддержка для распаковки запроса gzip на сервере. Также связаны: Отправка gzip-данных в WebRequest?, которая указывает на проблему код.