【问题标题】:Read error response body in Java在 Java 中读取错误响应正文
【发布时间】:2010-10-11 10:17:54
【问题描述】:

在 Java 中,当 HTTP 结果为 404 范围时,此代码会引发异常:

URL url = new URL("http://stackoverflow.com/asdf404notfound");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.getInputStream(); // throws!

就我而言,我碰巧知道内容是 404,但我还是想阅读响应的正文。

(在我的实际情况下,响应代码是 403,但响应正文解释了拒绝的原因,我想向用户显示。)

如何访问响应正文?

【问题讨论】:

  • 您确定服务器正在发送正文吗?
  • @jdigital:HttpURLConnection.getInputStream() 抛出的异常是 java.io.FileNotFoundException。 (主要是为了更好的谷歌搜索而提到这一点。)

标签: java http httpurlconnection


【解决方案1】:

Here is the bug report(关闭,不会修复,不是错误)。

他们的建议是这样编码:

HttpURLConnection httpConn = (HttpURLConnection)_urlConnection;
InputStream _is;
if (httpConn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
    _is = httpConn.getInputStream();
} else {
     /* error from server */
    _is = httpConn.getErrorStream();
}

【讨论】:

  • 您不想在响应代码 >= 400 时获取错误流,而不是相反吗?
  • 如果出现错误,getInputStream() 会抛出 IO Exception。您应该使用 getErrorStream() 捕获异常并从错误流中读取。这似乎是比检查 httpresponse 代码更好的方法。
  • 问题是,如果您阅读 HttpUrlConnection.getErrorStream() 代码,您会发现它总是返回 null。 (Java 6) :-(
  • 其他成功代码比如“201 CREATED”不会在这里失败吗?
  • 错误报告建议检查httpConn.getResponseCode() &gt;= 400(他们的解决方法有错误,翻转输入流以使用)
【解决方案2】:

这与我遇到的问题相同: 如果您尝试从连接中读取 getInputStream()HttpUrlConnection 将返回 FileNotFoundException
当状态码高于 400 时,您应该改用 getErrorStream()

不止于此,请注意,因为成功状态码不仅200,甚至201、204等也经常被用作成功状态。

这是我如何管理它的示例

... connection code code code ...

// Get the response code 
int statusCode = connection.getResponseCode();

InputStream is = null;

if (statusCode >= 200 && statusCode < 400) {
   // Create an InputStream in order to extract the response object
   is = connection.getInputStream();
}
else {
   is = connection.getErrorStream();
}

... callback/response to your handler....

通过这种方式,您将能够在成功和错误情况下获得所需的响应。

希望这会有所帮助!

【讨论】:

    【解决方案3】:

    在 .Net 中,您拥有 WebException 的 Response 属性,可以在异常情况下访问流。所以我想这对 Java 来说是一个好方法,...

    private InputStream dispatch(HttpURLConnection http) throws Exception {
        try {
            return http.getInputStream();
        } catch(Exception ex) {
            return http.getErrorStream();
        }
    }
    

    或者我使用的实现。 (可能需要更改编码或其他内容。在当前环境中工作。)

    private String dispatch(HttpURLConnection http) throws Exception {
        try {
            return readStream(http.getInputStream());
        } catch(Exception ex) {
            readAndThrowError(http);
            return null; // <- never gets here, previous statement throws an error
        }
    }
    
    private void readAndThrowError(HttpURLConnection http) throws Exception {
        if (http.getContentLengthLong() > 0 && http.getContentType().contains("application/json")) {
            String json = this.readStream(http.getErrorStream());
            Object oson = this.mapper.readValue(json, Object.class);
            json = this.mapper.writer().withDefaultPrettyPrinter().writeValueAsString(oson);
            throw new IllegalStateException(http.getResponseCode() + " " + http.getResponseMessage() + "\n" + json);
        } else {
            throw new IllegalStateException(http.getResponseCode() + " " + http.getResponseMessage());
        }
    }
    
    private String readStream(InputStream stream) throws Exception {
        StringBuilder builder = new StringBuilder();
        try (BufferedReader in = new BufferedReader(new InputStreamReader(stream))) {
            String line;
            while ((line = in.readLine()) != null) {
                builder.append(line); // + "\r\n"(no need, json has no line breaks!)
            }
            in.close();
        }
        System.out.println("JSON: " + builder.toString());
        return builder.toString();
    }
    

    【讨论】:

    • 这应该是公认的答案...我想知道为什么人们仍然验证幻数而不是处理异常...
    • 我想知道为什么这不是公认的答案。帮了我很多。谢谢!
    【解决方案4】:

    我知道这并不能直接回答这个问题,但您可能不想使用 Sun 提供的 HTTP 连接库,而是查看Commons HttpClient,它(在我看来)有一个更简单的 API一起工作。

    【讨论】:

    • 我不同意。只要您做真正简单的事情,Sun 的 API 就容易多了。通过简单的东西,我的意思是一个没有太多错误处理的 GET,这对于很多情况来说已经足够了。当然 HttpClient 在功能上要优越得多。
    • 截至 2014 年,最好的可能是 OkHttp(打开 URL 时实际上返回 HttpURLConnection 实例)。尤其是在 Android 上,它可以帮助您避免普通 HttpURLConnection 和 Apache HttpClient 的一些讨厌的问题。
    【解决方案5】:

    先检查响应码,然后使用HttpURLConnection.getErrorStream()

    【讨论】:

      【解决方案6】:
      InputStream is = null;
      if (httpConn.getResponseCode() !=200) {
          is = httpConn.getErrorStream();
      } else {
           /* error from server */
          is = httpConn.getInputStream();
      }
      

      【讨论】:

      • 其他成功代码比如“201 CREATED”不会在这里失败吗?
      • 是的@Rich,这就是为什么最好这样做:if (httpConn.getResponseCode() &lt; HttpURLConnection.HTTP_BAD_REQUEST) {
      【解决方案7】:

      我的运行代码。

        HttpURLConnection httpConn = (HttpURLConnection) urlConn;    
       if (httpConn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
                              in = new InputStreamReader(urlConn.getInputStream());
                              BufferedReader bufferedReader = new BufferedReader(in);
                              if (bufferedReader != null) {
                                  int cp;
                                  while ((cp = bufferedReader.read()) != -1) {
                                      sb.append((char) cp);
                                  }
                                  bufferedReader.close();
                              }
                                  in.close();
      
                          } else {
                              /* error from server */
                              in = new InputStreamReader(httpConn.getErrorStream());
                          BufferedReader bufferedReader = new BufferedReader(in);
                          if (bufferedReader != null) {
                              int cp;
                              while ((cp = bufferedReader.read()) != -1) {
                                  sb.append((char) cp);
                              }
                              bufferedReader.close();
                          }    
                          in.close();
                          }
                          System.out.println("sb="+sb);
      

      【讨论】:

      • 这真的很糟糕。正确的版本应该设置为常规流或错误流,然后从 if() 中读取只有一个序列。这段代码是丑陋的冗余。
      【解决方案8】:

      如何在 java 中读取 404 响应正文:

      使用 Apache 库 - https://hc.apache.org/httpcomponents-client-4.5.x/httpclient/apidocs/

      或 Java 11 - https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.html

      下面给出的片段使用 Apache:

      import org.apache.http.impl.client.CloseableHttpClient;
      import org.apache.http.impl.client.HttpClients;
      import org.apache.http.client.methods.CloseableHttpResponse;
      import org.apache.http.client.methods.HttpGet;
      import org.apache.http.util.EntityUtils;
      
      CloseableHttpClient client = HttpClients.createDefault();
      CloseableHttpResponse resp = client.execute(new HttpGet(domainName + "/blablablabla.html"));
      String response = EntityUtils.toString(resp.getEntity());
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-05-10
        • 1970-01-01
        • 2021-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多