Java에서 오류 응답 본문 읽기


93

Java에서이 코드는 HTTP 결과가 404 범위 일 때 예외를 발생시킵니다.

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

제 경우에는 콘텐츠가 404라는 것을 알고 있지만 어쨌든 응답 본문을 읽고 싶습니다.

(실제로는 응답 코드가 403이지만 응답 본문에 거부 이유가 설명되어 있으므로 사용자에게 표시하고 싶습니다.)

응답 본문에 어떻게 액세스 할 수 있습니까?


서버가 본문을 보내고 있습니까?
Hank Gay

2
@jdigital : HttpURLConnection.getInputStream ()에 의해 throw 된 예외는 java.io.FileNotFoundException입니다. (주로 더 나은 googlability이 언급.)
Jonik

답변:


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-04-13

3
오류가 발생한 경우 getInputStream ()은 IO 예외를 발생시킵니다. 예외를 포착하고 getErrorStream ()을 사용하여 오류 스트림에서 읽어야합니다. 이것은 httpresponse 코드를 확인하는 것보다 더 나은 접근 방식 인 것 같습니다.
Sudarshan Bhat 2012

3
문제는 HttpUrlConnection.getErrorStream () 코드를 읽으면 항상 null을 반환한다는 것을 알 수 있다는 것입니다. (Java 6) :-(
Gangnus 2014 년

6
"201 CREATED"와 같은 다른 성공 코드가 여기서 실패하지 않습니까?
Rich

4
버그 보고서는 확인을 제안합니다 httpConn.getResponseCode() >= 400(그리고 해결 방법에 오류가있어 사용할 입력 스트림을 뒤집습니다)
Dag

14

내가 가진 것과 동일한 문제 입니다. 연결에서 읽으려고하면 HttpUrlConnection반환 FileNotFoundException됩니다 getInputStream().
대신 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를 살펴보고 싶을 수 있습니다. Commons HttpClient 는 작업하기 훨씬 더 쉬운 API를 가지고 있습니다.


4
나는 다를 것을 간청한다. Sun의 API는 정말 간단한 작업을 수행하는 한 훨씬 쉽습니다. 간단히 말해서 너무 많은 오류 처리가없는 GET을 의미하며 이는 많은 경우에 충분합니다. 물론 HttpClient는 기능면에서 훨씬 우수합니다.
Michael Piefel

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

예 @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

자바에서 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());
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.