Affects: Spring Framework 3.2.3
Spring RestTemplate
fails giving an answer if the server responds with an illegal HTTP Content-Type
like CSV
instead of text/csv
.
Of course it is bad that the server returns such a content-type, but it would still be good if RestTemplate
had a fallback, at least for well-known types like byte[]
and String
.
We use RestTemplate
to load a CSV file from a system with:
restTemplate.getForEntity("http://server/something.csv", byte[].class);
When the server responds with a bad Content-Type
like CSV
, then:
MediaType.parseMediaType()
throws anInvalidMediaTypeException
HttpMessageConverterExtractor.extractData()
doesn't catch it.- It seems that
null
would be a possible fallback, because its only used in logs andcanRead()
allows it.
Comment From: bclozel
Thanks for the proposal, but I think that such unspecified behavior is hard to implement in Spring Framework as opinions can diverge pretty quickly there. Other applications might already rely on the fact that they're getting exceptions for this behavior and not a fallback that would be surprising for them.
Instead, I would suggest using a custom interceptor for dealing with such misbehaving servers in a way that fits your use case. Something like:
public class MyInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
return new ClientHttpResponseWrapper(response);
}
static class ClientHttpResponseWrapper implements ClientHttpResponse {
private final ClientHttpResponse delegate;
private final HttpHeaders headers;
public ClientHttpResponseWrapper(ClientHttpResponse delegate) {
this.delegate = delegate;
HttpHeaders originalHeaders = new HttpHeaders(delegate.getHeaders());
if (Objects.equals(originalHeaders.getFirst(HttpHeaders.CONTENT_TYPE), "csv")) {
originalHeaders.setContentType(MediaType.parseMediaType("text/csv"));
}
this.headers = HttpHeaders.readOnlyHttpHeaders(originalHeaders);
}
@Override
public HttpStatusCode getStatusCode() throws IOException {
return this.delegate.getStatusCode();
}
@Override
public String getStatusText() throws IOException {
return this.delegate.getStatusText();
}
@Override
public void close() {
this.delegate.close();
}
@Override
public InputStream getBody() throws IOException {
return this.delegate.getBody();
}
@Override
public HttpHeaders getHeaders() {
return this.headers;
}
}
}