如何使用Spring RestTemplate压缩HTTP请求? [英] How to zip- compress HTTP request with Spring RestTemplate?
问题描述
如何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.
此方法的缺点是它不支持流传输,因为ClientHttpRequestInterceptor
以byte[]
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屋!