I am trying to intercept and log all the request-responses. To make requests i am using RestTemplate.exchange()
.
When i make a GET
request and get an 4**
error i can call the ClientHttpResponse.getBody(
) and can access the response body but for PUT
and POST
requests ClientHttpResponse.getBody()
method throws an exception.
What might be causing this and how can i get the response body for POST
and PUT
requests as well?
This is where i make the request:
apiResponse = restTemplate.exchange(url, vCloudRequest.getHttpMethod(), entity, responseType);
This is the part of the interceptor that gets the exception:
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
String requestString = new String(body);
String responseString = new
// Below line throws exception
String(ByteStreams.toByteArray(response.getBody()), Charset.forName("UTF-8"));
This is the stack.
Caused by: java.io.IOException: Server returned HTTP response code: 403 for URL: https://176.235.57.11/api/admin/org/bd154aaf-2e7c-446d-91be-f0a45138476b/users
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1876)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at org.springframework.http.client.SimpleClientHttpResponse.getBody(SimpleClientHttpResponse.java:85)
at org.springframework.http.client.BufferingClientHttpResponseWrapper.getBody(BufferingClientHttpResponseWrapper.java:69)
at roma.api_utils.model.Interceptors.RequestLoggingInterceptor.intercept(RequestLoggingInterceptor.java:39)
at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:86)
at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:70)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:652)
Update :
When i call response.getStatusCode()
before calling response.getBody()
it doesn't throw IOException
.
Basic knowledge:
HttpURLConnection
has two similar fields, errorStream
and inputStream
. When we invoke its getInputSteam
method, it checks whether the response has an error code. If so, it throws an IOException
and records it- that's why you got the exception. Furthermore, it also copies the contents in inputStream
to errorStream
, thus we can get its response body by invoking its getErrorStream
method. This is exactly what SimpleClientHttpResponse does with its getBody
method:
@Override
public InputStream getBody() throws IOException {
InputStream errorStream = this.connection.getErrorStream();
this.responseStream =
(errorStream != null ? errorStream : this.connection.getInputStream());
return this.responseStream;
}
It first checks if errorStream
is not null. If true, it returns it. If false, it calls connection.getInputStream()
and returns that.
Now here are the answers
response.getBody()
not throw an IOException after you called response.getStatusCode()
? It is because getStatusCode
calls getInputStream
internally. Thus, errorStream
will be not null when getBody
is called.org.springframework.http.client.SimpleBufferingClientHttpRequest#executeInternal
..
@Override
protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput)
throws IOException {
addHeaders(this.connection, headers);
// JDK <1.8 doesn't support getOutputStream with HTTP DELETE
if (HttpMethod.DELETE == getMethod() && bufferedOutput.length == 0) {
this.connection.setDoOutput(false);
}
if (this.connection.getDoOutput() && this.outputStreaming) {
this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
}
this.connection.connect();
if (this.connection.getDoOutput()) {
FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
}
else {
// Immediately trigger the request in a no-output scenario as well
this.connection.getResponseCode();
}
return new SimpleClientHttpResponse(this.connection);
}
It eagerly executes this.connection.getResponseCode();
when the http method is GET.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With