读取Java中的错误响应正文


93

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

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

就我而言,我碰巧知道内容是404,但无论如何我还是想阅读响应的内容。

(在我的实际情况下,响应代码为403,但是响应的主体说明了拒绝的原因,我希望向用户显示该信息。)

如何访问响应正文?


您确定服务器正在发送正文吗?
汉克·盖伊

2
@jdigital:HttpURLConnection.getInputStream()引发的异常是java.io.FileNotFoundException。(主要是为了获得更好的Googlgability提及这一点。)
Jonik

Answers:


172

这是错误报告(关闭,无法修复,不是错误)。

他们的建议是这样编码:

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

5
当响应代码> = 400而不是相反时,您是否不想获得错误流?
Stephen Swensen 2010年

3
如果发生错误,getInputStream()将引发IO异常。您应该捕获异常并使用getErrorStream()从错误流中读取。这似乎比检查httpresponse代码更好。
Sudarshan Bhat

3
问题是,如果您阅读HttpUrlConnection.getErrorStream()代码,则会看到它总是返回null。(Java 6):
Gangnus

6
其他成功代码(例如“ 201 CREATED”)不会在这里失败吗?
丰富,

4
错误报告建议进行检查httpConn.getResponseCode() >= 400(其变通方法有错误,请翻转输入流以使用)
Dag

14

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

除此之外,请注意,因为成功状态代码不仅是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....

这样,无论是成功案例还是错误案例,您都可以获得所需的响应。

希望这可以帮助!


13

在.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();
}

这应该是公认的答案...我不知道为什么人们仍然验证魔术数字而不是处理异常...
SparK

我想知道为什么这不是公认的答案。对我有很大帮助。谢谢!
Nikhil Jain

2

我知道这并不能直接回答问题,但是您可能不希望使用Sun提供的HTTP连接库,而应看看Commons HttpClient,它(我认为)的API使用起来要容易得多。


4
我不敢苟同。只要您做的非常简单,Sun的API就容易得多。用简单的话来说,我的意思是只是一个没有太多错误处理的GET,这对于很多情况来说已经足够了。当然,HttpClient在功能上要优越得多。
Michael Piefel 2011年

截至2014年,最好的方法可能是OkHttp(在打开URL时实际上返回HttpURLConnection实例)。特别是在Android上,它可以帮助您避免HttpURLConnection和Apache HttpClient的讨厌问题。
Jonik


1
InputStream is = null;
if (httpConn.getResponseCode() !=200) {
    is = httpConn.getErrorStream();
} else {
     /* error from server */
    is = httpConn.getInputStream();
}

4
其他成功代码(例如“ 201 CREATED”)不会在这里失败吗?
丰富

是的@Rich,这就是为什么最好这样做:if (httpConn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
AO_

1

我的运行代码。

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

0

如何在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());
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.