อ่านเนื้อหาการตอบสนองข้อผิดพลาดใน 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 () คือ 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

3
ในกรณีที่เกิดข้อผิดพลาด getInputStream () จะส่งข้อยกเว้น IO คุณควรจับข้อยกเว้นและอ่านจากสตรีมข้อผิดพลาดโดยใช้ getErrorStream () ดูเหมือนว่าจะเป็นแนวทางที่ดีกว่าการตรวจสอบโค้ด httpresponse
Sudarshan Bhat

3
ปัญหาคือถ้าคุณอ่านโค้ด HttpUrlConnection.getErrorStream () คุณจะเห็นว่ามันส่งคืนค่า null เสมอ (Java 6) :-(
Gangnus

6
รหัสความสำเร็จอื่น ๆ เช่น "201 CREATED" จะไม่ล้มเหลวที่นี่หรือ
รวย

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 ที่ให้การเข้าถึงสตรีม ON ข้อยกเว้น ดังนั้นฉันเดาว่านี่เป็นวิธีที่ดีสำหรับ 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

ฉันรู้ว่าสิ่งนี้ไม่ได้ตอบคำถามโดยตรง แต่แทนที่จะใช้ไลบรารีการเชื่อมต่อ HTTP ที่ Sun จัดเตรียมไว้ให้คุณอาจต้องการดูCommons HttpClientซึ่ง (ในความคิดของฉัน) มี API ที่ใช้งานง่ายกว่ามาก


4
ฉันขอแตกต่าง API จาก Sun นั้นง่ายกว่ามากตราบใดที่คุณทำสิ่งที่ง่ายจริงๆ โดยทั่วไปฉันหมายถึง GET ที่ไม่มีการจัดการข้อผิดพลาดมากเกินไปซึ่งเพียงพอสำหรับหลาย ๆ กรณี แน่นอนว่า HttpClient มีฟังก์ชันการทำงานที่เหนือกว่ามาก
Michael Piefel

ในปี 2014 สิ่งที่ดีที่สุดอาจเป็นOkHttp (ซึ่งส่งคืนอินสแตนซ์ HttpURLConnection เมื่อเปิด URL) โดยเฉพาะอย่างยิ่งบน 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" จะไม่ล้มเหลวที่นี่หรือ
รวย

ใช่ @ ริชนั่นคือเหตุผลที่ควรทำ: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 ใน java:

ใช้ไลบรารี 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.