Đọc nội dung phản hồi lỗi trong Java


93

Trong Java, mã này ném một ngoại lệ khi kết quả HTTP là phạm vi 404:

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

Trong trường hợp của tôi, tôi tình cờ biết rằng nội dung là 404, nhưng tôi vẫn muốn đọc phần nội dung của câu trả lời.

(Trong trường hợp thực tế của tôi, mã phản hồi là 403, nhưng phần nội dung của phản hồi giải thích lý do từ chối và tôi muốn hiển thị điều đó cho người dùng.)

Làm cách nào để truy cập vào cơ quan phản hồi?


Bạn có chắc máy chủ đang gửi nội dung không?
Hank Gay

2
@jdigital: ngoại lệ được ném bởi HttpURLConnection.getInputStream () là java.io.FileNotFoundException. (Chủ yếu đề cập đến vấn đề này để có khả năng truy cập tốt hơn.)
Jonik

Câu trả lời:


172

Đây là báo cáo lỗi (đóng, sẽ không sửa, không phải lỗi).

Lời khuyên của họ là viết mã như thế này:

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

5
Bạn có muốn nhận dòng lỗi khi mã phản hồi> = 400, thay vì ngược lại?
Stephen Swensen

3
Trong trường hợp có lỗi, getInputStream () sẽ ném IO Exception. Bạn nên bắt ngoại lệ và đọc từ luồng lỗi bằng getErrorStream (). Đây dường như là một cách tiếp cận tốt hơn so với việc kiểm tra trên mã httpresponse.
Sudarshan Bhat

3
Vấn đề là nếu bạn đọc mã HttpUrlConnection.getErrorStream (), bạn sẽ thấy rằng nó LUÔN LUÔN trả về null. (Java 6) :-(
Gangnus

6
Các mã thành công khác như "201 CREATED" sẽ không thành công ở đây chứ?
Giàu có

4
Báo cáo lỗi đề xuất kiểm tra httpConn.getResponseCode() >= 400(và công việc xung quanh của họ có lỗi, lật các dòng đầu vào để sử dụng)
Dag

14

Đó là vấn đề tương tự mà tôi gặp phải: HttpUrlConnectiontrả về FileNotFoundExceptionnếu bạn cố gắng đọc getInputStream()từ kết nối.
Thay vào đó, bạn nên sử dụng getErrorStream()khi mã trạng thái cao hơn 400.

Hơn thế nữa, hãy cẩn thận vì nó không chỉ 200 là mã trạng thái thành công, thậm chí 201, 204, v.v. thường được sử dụng làm trạng thái thành công.

Đây là một ví dụ về cách tôi đã quản lý nó

... 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....

Bằng cách này, bạn sẽ có thể nhận được phản hồi cần thiết trong cả trường hợp thành công và lỗi.

Hi vọng điêu nay co ich!


13

Trong .Net, bạn có thuộc tính Đáp ứng của WebException cung cấp quyền truy cập vào luồng BẬT một ngoại lệ. Vì vậy, tôi đoán đây là một cách tốt cho Java, ...

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

Hoặc một triển khai tôi đã sử dụng. (Có thể cần thay đổi để mã hóa hoặc những thứ khác. Hoạt động trong môi trường hiện tại.)

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

Điều này sẽ là câu trả lời được chấp nhận ... Tôi tự hỏi tại sao mọi người vẫn xác minh số kỳ diệu thay vì ngoại lệ xử lý ...
Spark

Tôi tự hỏi tại sao điều này không phải là câu trả lời được chấp nhận. Đã giúp tôi rất nhiều. Cảm ơn!
Nikhil Jain

2

Tôi biết rằng điều này không trả lời câu hỏi trực tiếp, nhưng thay vì sử dụng thư viện kết nối HTTP do Sun cung cấp, bạn có thể muốn xem Commons HttpClient , (theo ý kiến ​​của tôi) có API dễ làm việc hơn nhiều.


4
Tôi có ý kiến ​​khác. API từ Sun dễ dàng hơn nhiều, miễn là bạn làm những việc thực sự đơn giản. Bởi đơn giản, ý tôi chỉ là GET mà không cần xử lý quá nhiều lỗi, điều này là đủ cho rất nhiều trường hợp. Tất nhiên HttpClient vượt trội hơn nhiều về chức năng.
Michael Piefel

Kể từ năm 2014, tốt nhất có thể là OkHttp (thực sự trả về các phiên bản HttpURLConnection khi mở một URL). Đặc biệt là trên Android, nó có thể giúp bạn tránh một số vấn đề khó chịu của cả HttpURLConnection và Apache HttpClient.
Jonik

2

Đầu tiên hãy kiểm tra mã phản hồi và sau đó sử dụng HttpURLConnection.getErrorStream()


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

4
Các mã thành công khác như "201 CREATED" sẽ không thành công ở đây chứ?
Phong phú

Có @Rich, đó là lý do tại sao tốt hơn nên làm:if (httpConn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
AO_

1

Mã đang chạy của tôi.

  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

Cách đọc nội dung phản hồi 404 trong java:

Sử dụng thư viện Apache - https://hc.apache.org/httpcomponents-client-4.5.x/httpclient/apidocs/

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

Đoạn mã dưới đây sử dụng 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());
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.