RestTemplate response.getBody对put和post请求的4**和5**错误抛出异常但对get请求工作正常

Sal*_*kci 2 java spring http resttemplate

我试图拦截并记录所有请求 - 响应.提出我正在使用的请求RestTemplate.exchange().

当我发出GET请求并得到4**错误时,我可以调用ClientHttpResponse.getBody()并且可以访问响应主体,但for PUTPOSTrequests ClientHttpResponse.getBody()方法会抛出异常.

可能导致这种情况的原因以及我如何获得响应主体POSTPUT请求?

这是我提出请求的地方:

apiResponse = restTemplate.exchange(url, vCloudRequest.getHttpMethod(), entity, responseType);
Run Code Online (Sandbox Code Playgroud)

这是获取异常的拦截器的一部分:

@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"));
Run Code Online (Sandbox Code Playgroud)

这是堆栈.

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)
Run Code Online (Sandbox Code Playgroud)

更新:

当我在打电话response.getStatusCode()之前打电话response.getBody()它不扔IOException.

小智 9

基础知识:

HttpURLConnection有两个相似的字段,errorStream并且inputStream,当我们调用它的getInputSteam方法时,它检查响应是否有错误代码.如此,它会抛出IOException并记录它,这就是你得到异常的原因;此外,它还将内容复制inputStreamerrorStream因此我们可以通过调用它的getErrorStream方法来获取它的响应体,这正是SimpleClientHttpResponse对其getBody方法的作用:

    @Override
    public InputStream getBody() throws IOException {
        InputStream errorStream = this.connection.getErrorStream();
        this.responseStream = 
(errorStream != null ? errorStream : this.connection.getInputStream());
        return this.responseStream;
    }
Run Code Online (Sandbox Code Playgroud)

它首先检查if是否errorStream为null,如果为false,则返回它,如果为true,则调用connection.getInputStream()并返回

现在就是答案

  1. 为什么调用response.getBody()不抛出IOException你叫后response.getStatusCode(),这是因为getStatusCode电话getInputStreaminternally.Thus,errorStream将不为空时getBody被调用
  2. 为何在http方法为GET时不抛出异常.检查方法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);
}
Run Code Online (Sandbox Code Playgroud)

this.connection.getResponseCode();当http方法是GET时, 它急切地执行