FileNotFoundException trong khi lấy đối tượng InputStream từ HttpURLConnection


109

Tôi đang cố gắng gửi một yêu cầu bài đăng đến một url bằng HttpURLConnection (để sử dụng cUrl trong java). Nội dung của yêu cầu là xml và ở điểm cuối, ứng dụng xử lý xml và lưu trữ một bản ghi vào cơ sở dữ liệu và sau đó gửi lại phản hồi dưới dạng chuỗi xml. Ứng dụng được lưu trữ trên apache-tomcat cục bộ.

Khi tôi thực thi mã này từ thiết bị đầu cuối, một hàng được thêm vào db như mong đợi. Nhưng một ngoại lệ được đưa ra như sau khi lấy InputStream từ kết nối

java.io.FileNotFoundException: http://localhost:8080/myapp/service/generate
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1401)
    at org.kodeplay.helloworld.HttpCurl.main(HttpCurl.java:30)

Đây là mã

public class HttpCurl {
    public static void main(String [] args) {

        HttpURLConnection con;

        try {
            con = (HttpURLConnection) new URL("http://localhost:8080/myapp/service/generate").openConnection();
            con.setRequestMethod("POST");
            con.setDoOutput(true);
            con.setDoInput(true);

            File xmlFile = new File("test.xml");

            String xml = ReadWriteTextFile.getContents(xmlFile);                

            con.getOutputStream().write(xml.getBytes("UTF-8"));
            InputStream response = con.getInputStream();

            BufferedReader reader = new BufferedReader(new InputStreamReader(response));
            for (String line ; (line = reader.readLine()) != null;) {
                System.out.println(line);
            }
            reader.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  }

Nó khó hiểu vì ngoại lệ được truy tìm dòng InputStream response = con.getInputStream();và dường như không có bất kỳ tệp nào liên quan đến FileNotFoundException.

Khi tôi cố gắng mở kết nối trực tiếp đến tệp xml, nó không đưa ra ngoại lệ này.

Ứng dụng dịch vụ sử dụng khung công tác mùa xuân và Jaxb2Marshaller để tạo xml phản hồi.

Lớp ReadWriteTextFile được lấy từ đây

Cảm ơn.

Chỉnh sửa: Nó lưu dữ liệu trong DB và gửi lại mã trạng thái phản hồi 404 cùng một lúc.

Tôi cũng đã thử làm một cuộn tóc bằng php và in ra kết quả CURLINFO_HTTP_CODElà 200.

Bất kỳ ý tưởng về cách làm thế nào để gỡ lỗi này? Cả dịch vụ và máy khách đều nằm trên máy chủ cục bộ.

Đã giải quyết: Tôi có thể giải quyết vấn đề sau khi tham khảo câu trả lời trên chính SO.

Có vẻ như HttpURLConnection luôn trả về phản hồi 404 khi kết nối với url có cổng không chuẩn.

Thêm những dòng này đã giải quyết nó

con.setRequestProperty("User-Agent","Mozilla/5.0 ( compatible ) ");
con.setRequestProperty("Accept","*/*");

1
"Khi tôi thực thi mã này từ thiết bị đầu cuối" - mã nào? Không rõ những gì đang hoạt động và những gì không hoạt động.
Jon Skeet

HttpCurl là tên của lớp có phương thức chính này. Lớp này được biên soạn và chạy từ nhà ga
naiquevin

3
Tôi đã gặp vấn đề tương tự nhưng không có giải pháp nào ở đây hoạt động. Cuối cùng tôi đã phát hiện ra đó là sự cố với Java 1.7.0_05 và cập nhật lên phiên bản mới nhất 1.7.0_21 và sự cố đã biến mất. Tôi cũng nhận ra sự cố không xảy ra trong Java 1.6. Chỉ là một FYI cho bất kỳ ai còn mắc kẹt.
Steven

Các bạn ơi! xem nhận xét "Đã giải quyết" về câu hỏi hơn là câu trả lời!
김준호

Câu trả lời:


130

Tôi không biết về sự kết hợp Spring / JAXB của bạn, nhưng dịch vụ web REST trung bình sẽ không trả về nội dung phản hồi trên POST / PUT, chỉ là trạng thái phản hồi . Bạn muốn xác định nó thay vì cơ thể.

Thay thế

InputStream response = con.getInputStream();

bởi

int status = con.getResponseCode();

Tất cả các mã trạng thái có sẵn và ý nghĩa của chúng đều có trong thông số kỹ thuật HTTP, như được liên kết trước đó. Bản thân webservice cũng phải đi kèm với một số tài liệu tổng quan về tất cả các mã trạng thái được hỗ trợ bởi webservice và ý nghĩa đặc biệt của chúng, nếu có.

Nếu trạng thái bắt đầu bằng 4nnhoặc 5nn, getErrorStream()thay vào đó bạn muốn sử dụng để đọc nội dung phản hồi có thể chứa chi tiết lỗi.

InputStream error = con.getErrorStream();

Ok, tôi đã thử điều này và nó trả về trạng thái 404. Nhưng lạ thay, nó cũng đang lưu trong DB! Cũng từ những gì bạn đề cập, nó có nghĩa là bất kỳ dịch vụ REST nào sẽ chỉ trả về một mã trạng thái? Điều gì sẽ xảy ra nếu tôi muốn trả lại nhiều thông tin hơn như thông báo lỗi xác thực xml hoặc url nếu bài đăng thành công?
naiquevin

Có, đối với các yêu cầu sửa đổi như POST / PUT / etc, nó thường sẽ không trả về một phần thân. Bạn thường muốn xác định trạng thái phản hồi trước khi đọc luồng đầu vào hoặc luồng lỗi. Tôi đã thêm một số chi tiết vào câu trả lời. Nhưng nếu nó thực sự trả về trạng thái 404 thì có thể có một số lỗi trong dịch vụ web. Tôi sẽ báo cáo với người bảo trì nó.
BalusC

Trong trường hợp này, người duy trì dịch vụ là tôi! .. Vâng, tôi đã thử làm một curl bằng php và nó trả về 200 (đã chỉnh sửa câu hỏi của tôi) Cũng đã thử getErrorStream()theo đề xuất. Nó ném một NullPointerException vào new InputStreamReader(con.getErrorStream()).
naiquevin

Xin lỗi, tôi không nổi tiếng với dịch vụ web Spring. Tôi chỉ thực hành kinh nghiệm với JAX-WS / RS từ API Java EE 5/6 tiêu chuẩn. Tôi khuyên bạn nên đặt một điểm ngắt trên phương thức chịu trách nhiệm xử lý tệp XML và sau đó bước xa hơn từ đó.
BalusC

Hành vi này có vẻ rất không hữu ích, đặc biệt vì nó làm cho việc đề cập đến mọi thứ theo một URLConnectionvấn đề chung chung hơn . Tôi tự hỏi tại sao những kẻ Java không chỉ đơn giản là thực hiện getInputStream()HttpUrlConnectiondọc theo dòng return responseCode == 200 ? super.getInputStream() : this.getErrorStream(). Nhưng dù sao đi nữa; câu trả lời nhiều thông tin, +1.
aroth

51

FileNotFound chỉ là một ngoại lệ đáng tiếc được sử dụng để chỉ ra rằng máy chủ web trả về 404.


1
Điều đó không giải thích tại sao hàng được thêm vào DB như OP đã nêu.
BalusC

@BalusC: Trừ khi máy chủ được thêm một hàng và sau đó trả về một 404.
Jon Skeet

có vẻ như nó đang cư xử theo cách này. Nó có nghĩa là gì ?
naiquevin

@naiquevin: Thật khó để nói, nhưng vì đó là một dịch vụ chạy cục bộ, bạn có thể tự gỡ lỗi nó.
Jon Skeet

7
HttpURLConnection cũng ném FileNotFoundException cho 403 phản hồi (và có thể là những phản hồi khác). ( Có vẻ như ngay cả khi cơ quan phản hồi không trống.) Dù sao, hãy luôn điều tra getResponseCode()trước khi gọi getInputStream().
Jonik

29

Đối với bất kỳ ai gặp sự cố này trong tương lai, lý do là vì mã trạng thái là 404 (hoặc trong trường hợp của tôi là 500). Có vẻ như InpuStreamhàm sẽ báo lỗi khi mã trạng thái không phải là 200.

Trong trường hợp của tôi, tôi kiểm soát máy chủ của riêng mình và đang trả về mã trạng thái 500 để cho biết đã xảy ra lỗi. Mặc dù tôi cũng gửi một phần nội dung với một chuỗi thông báo nêu chi tiết về lỗi, lỗi inputstreamđã tạo ra một lỗi bất kể phần nội dung đó hoàn toàn có thể đọc được.

Nếu bạn kiểm soát máy chủ của mình, tôi cho rằng điều này có thể được xử lý bằng cách gửi cho bạn mã trạng thái 200 và sau đó xử lý bất kỳ phản hồi lỗi chuỗi nào.


21
Nói rõ hơn, bạn chỉ đang xử lý sai. Bạn nên sử dụng connection.getResponseCode để kiểm tra xem nó có ổn không. Sau đó, sử dụng connect.getErrorStream để lấy nội dung lỗi thay vì getInputStream. (hoặc bạn có thể sử dụng getResponseMessage) Bạn không nên gửi mã trạng thái 200 nếu đó là lỗi, hãy sử dụng mã lỗi http như dự định.
rekh127

5

Đối với bất kỳ ai khác tình cờ gặp phải điều này, điều tương tự đã xảy ra với tôi khi cố gắng gửi tiêu đề yêu cầu SOAP tới một dịch vụ SOAP. Vấn đề là một thứ tự sai trong mã, tôi đã yêu cầu luồng đầu vào trước khi gửi phần thân XML. Trong đoạn mã được cắt bên dưới, dòng InputStream in = conn.getInputStream();xuất hiện ngay sau ByteArrayOutputStream out = new ByteArrayOutputStream();đó là thứ tự không chính xác của mọi thứ.

ByteArrayOutputStream out = new ByteArrayOutputStream();
// send SOAP request as part of HTTP body 
byte[] data = request.getHttpBody().getBytes("UTF-8");
conn.getOutputStream().write(data); 

if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
  Log.d(TAG, "http response code is " + conn.getResponseCode());
  return null;
}

InputStream in = conn.getInputStream();

FileNotFound trong trường hợp này là một cách không may để mã hóa mã phản hồi HTTP 400.


FileNotFound là do kết nối không có luồng uput. Nó không liên quan gì đến mã phản hồi mã hóa 400. Bạn có thể lấy mã phản hồi bằng getResponseCode (). Sau đó, nếu đó không phải là HTTP_OK, bạn nên lấy phần thân bằng conn.getErrorStream () hoặc getResponseMessage ()
rekh127 12/1214

new ByteArrayOutputStream()không liên quan gì đến nó. Vấn đề là thứ tự giữa getInputStream()getResponseCode().
Marquis of Lorne,

4

FileNotFound trong trường hợp này có nghĩa là bạn nhận được 404 từ máy chủ của mình - có thể máy chủ không thích các yêu cầu "POST"?


Nhưng nó không lưu một bản ghi vào db. Jaxb2Marshaller có thể là vấn đề ở đây?
naiquevin

2
Điều này không chỉ xảy ra trong 404s. Nó cũng xảy ra đối với bất kỳ phản hồi nào có phần thân trống.
Dave Cameron

3
Câu trả lời này, thật không may, sai. FileNotFound trong tình huống này chỉ có nghĩa là HttpURLConnection # getInputStream () được gọi khi mã phản hồi trên 399, trong khi trong tình huống này, HttpURLConnection # getErrorStream () nên được gọi. OTOH, nếu máy chủ không chấp nhận POST, nó sẽ trả về phương pháp 405 Không được phép. Không liên quan đến FileNotFound được ném ở đó.
Michal M,

0

Giải pháp:
chỉ cần thay đổi localhost cho IP của PC
nếu bạn muốn biết điều này: Windows + r> cmd> ipconfig
Ví dụ: http: // 192.168.0.107 /directory/service/program.php?action=sendMột cái gì đó
chỉ cần thay thế 192.168 .0.107 cho IP của riêng bạn (không thử 127.0.0.1 vì nó giống với localhost )


-4

Hãy thay đổi

con = (HttpURLConnection) new URL("http://localhost:8080/myapp/service/generate").openConnection();

Đến

con = (HttpURLConnection) new URL("http://YOUR_IP:8080/myapp/service/generate").openConnection();

2
Thay đổi nó tại sao? OP đã tuyên bố cụ thể rằng dịch vụ đang chạy cục bộ.
Marquis of Lorne,

Trong trường hợp bạn cần lấy tài nguyên hình ảnh từ localhost, nó không hoạt động.
Phuoc Huynh
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.