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

标签 java spring http resttemplate

我正在尝试拦截并记录所有请求-响应。为了发出请求,我正在使用 RestTemplate.exchange()

当我发出 GET 请求并收到 4** 错误时,我可以调用 ClientHttpResponse.getBody() 并可以访问响应主体,但对于 PUTPOST 请求,ClientHttpResponse.getBody() 方法抛出异常。

这可能是什么原因造成的?我如何才能获得 POSTPUT 请求的响应主体?

这是我提出请求的地方:

apiResponse = restTemplate.exchange(url, vCloudRequest.getHttpMethod(), entity, responseType);

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

@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"));

这是堆栈。

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)

更新:

当我在调用 response.getBody() 之前调用 response.getStatusCode() 时,它不会抛出 IOException

最佳答案

基础知识:

HttpURLConnection 有两个相似的字段,errorStreaminputStream。当我们调用它的 getInputSteam 方法时,它会检查响应是否有错误代码。如果是这样,它会抛出一个 IOException 并记录它——这就是你得到异常的原因。此外,它还将inputStream中的内容复制到errorStream中,这样我们就可以通过调用它的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;
    }

它首先检查 errorStream 是否不为空。如果为真,则返回它。如果为假,它会调用 connection.getInputStream() 并返回它。

答案在这里

  1. 为什么在调用 response.getStatusCode() 之后调用 response.getBody() 不会抛出 IOException?这是因为 getStatusCode 在内部调用了 getInputStream。因此,当调用 getBody 时,errorStream 将不为空。
  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);
}

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

关于java - RestTemplate response.getBody 在 put 和 post 请求的 4** 和 5** 错误上抛出异常,但对于 get 请求工作正常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47429978/

相关文章:

Java 应用程序在命令提示符下执行命令

java - hibernate 搜索索引不起作用

spring - 从 Gmail 发送电子邮件在 CloudBees 上不起作用

ruby-on-rails - Rails API 中创建或更新操作的正确 HTTP 方法是什么?

java - 将 java 函数 URLDecoder.decode 应用于 Spark 3 中的整个列

java - 如何使用 JSON 将值从我的 android java 类传递到 php?

java - Selenium:获取 Last-Modified HTTP header ?

java - 如何使用 java 应用程序发出 Elastic search url 请求?

java - 在与量词匹配失败后,Java 的 matcher.find() 会保留什么样的状态?

java - 单例是有状态的吗?