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
.
You can use the following to accesss the response body in the interceptor. I did a quick unit test to confirm it works even on a POST with a 403 response.
However be careful, getBody returns an InputStream. Which means you can only read it once. You won't be able to read the same stream again outside the interceptor unless you provide a new response with a new body.
For
PUT
andPOST
, it depends on your target resource. If your target resource do not add anything in the response's body after aPUT
orPOST
request, it's normal to get an exception. In general, you know the resource that you send withPUT
orPOST
so you can just check the response's status to know if your resource had been created or modified. You do not need to check the response body again.Basic knowledge:
HttpURLConnection
has two similar fields,errorStream
andinputStream
,When we invoke itsgetInputSteam
method , it checks whether the response has an error code.if so,it throws anIOException
and records it,that's why you got the exception;Further more,it also copy the contents ininputStream
toerrorStream
,thus we can get its response body by invoking itsgetErrorStream
method,which is exactly what SimpleClientHttpResponse does with itsgetBody
method:it first checks if
errorStream
is null,if false,return it ,if true,callconnection.getInputStream()
and returnNow here is the answer
response.getBody()
doesn't throw IOException after you calledresponse.getStatusCode()
,it is becausegetStatusCode
callsgetInputStream
internally.Thus,errorStream
will be not null whengetBody
is calledorg.springframework.http.client.SimpleBufferingClientHttpRequest#executeInternal
..
it eagerly executes
this.connection.getResponseCode();
when http method is GETI had a similar requirement of logging every request and response. I wrote a filter and hooked into the filter chain.
The code looks like something below: