FileNotFoundException ขณะรับวัตถุ InputStream จาก HttpURLConnection


109

ฉันพยายามส่งคำขอโพสต์ไปยัง url โดยใช้ HttpURLConnection (สำหรับการใช้ cUrl ใน java) เนื้อหาของคำร้องขอคือ xml และที่จุดสิ้นสุดแอ็พพลิเคชันจะประมวลผล xml และจัดเก็บเร็กคอร์ดไปยังฐานข้อมูลจากนั้นส่งการตอบกลับในรูปแบบสตริง xml แอปนี้โฮสต์บน apache-tomcat ในเครื่อง

เมื่อฉันรันโค้ดนี้จากเทอร์มินัลแถวจะถูกเพิ่มไปยังฐานข้อมูลตามที่คาดไว้ แต่มีข้อยกเว้นเกิดขึ้นดังต่อไปนี้ในขณะที่รับ InputStream จากการเชื่อมต่อ

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)

นี่คือรหัส

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

มันสับสนเนื่องจากข้อยกเว้นถูกโยงไปยังบรรทัดInputStream response = con.getInputStream();และดูเหมือนจะไม่มีไฟล์ใด ๆ ที่เกี่ยวข้องกับ FileNotFoundException

เมื่อฉันพยายามเปิดการเชื่อมต่อกับไฟล์ xml โดยตรงมันไม่ได้ทำให้เกิดข้อยกเว้นนี้

แอปบริการใช้ Spring Framework และ Jaxb2Marshaller เพื่อสร้าง xml การตอบสนอง

คลาส ReadWriteTextFile ถูกนำมาจากที่นี่

ขอบคุณ.

แก้ไข: มันบันทึกข้อมูลในฐานข้อมูลและส่งกลับรหัสสถานะการตอบกลับ 404 ในเวลาเดียวกัน

ฉันลองทำ curl โดยใช้ php และพิมพ์ออกมาCURLINFO_HTTP_CODEซึ่งกลายเป็น 200

มีความคิดเห็นเกี่ยวกับการแก้ไขข้อบกพร่องนี้อย่างไร ทั้งบริการและไคลเอ็นต์อยู่บนเซิร์ฟเวอร์ภายใน

ได้รับการแก้ไข: ฉันสามารถแก้ปัญหาได้หลังจากอ้างถึงคำตอบของ SO เอง

ดูเหมือนว่า HttpURLConnection จะส่งกลับการตอบสนอง 404 เสมอเมื่อเชื่อมต่อกับ url ด้วยพอร์ตที่ไม่ได้มาตรฐาน

การเพิ่มบรรทัดเหล่านี้แก้ไขได้

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

1
"เมื่อฉันรันโค้ดนี้จากเทอร์มินัล" - รหัสใด ไม่ชัดเจนว่าอะไรได้ผลกับอะไรไม่ได้ผล
Jon Skeet

HttpCurl คือชื่อของคลาสที่มีเมธอดหลักนี้ ชั้นนี้รวบรวมและเรียกใช้จากอาคารผู้โดยสาร
naiquevin

3
ฉันประสบปัญหาเดียวกัน แต่วิธีแก้ปัญหาไม่ได้ผล ในที่สุดฉันก็พบว่ามันเป็นปัญหากับ Java 1.7.0_05 และอัปเดตเป็นเวอร์ชันล่าสุด 1.7.0_21 และปัญหาก็หายไป ฉันยังตระหนักว่าปัญหาไม่ได้เกิดขึ้นใน Java 1.6 แค่ FYI สำหรับใครที่ยังติดอยู่
Steven

พวก! ดูความคิดเห็นที่ "แก้ไขแล้ว" ในคำถามแทนที่จะเป็นคำตอบ!
김준호

อาจซ้ำกันของRead error response body ใน Java
Tony

คำตอบ:


130

ผมไม่ทราบว่าเกี่ยวกับการรวมกันในฤดูใบไม้ผลิ / JAXB ของคุณ แต่ส่วนที่เหลือเว็บเซอร์เฉลี่ยจะไม่กลับมาตอบสนองของร่างกายในการโพสต์ / PUT เพียงสถานะการตอบสนอง คุณต้องการกำหนดมันแทนร่างกาย

แทนที่

InputStream response = con.getInputStream();

โดย

int status = con.getResponseCode();

รหัสสถานะที่มีอยู่ทั้งหมดและความหมายมีอยู่ในข้อมูลจำเพาะ HTTP ตามที่ลิงก์มาก่อน นอกจากนี้เว็บเซิร์ฟเวอร์เองควรมาพร้อมกับเอกสารประกอบบางส่วนซึ่งจะรวมรหัสสถานะทั้งหมดที่บริการสนับสนุนโดยเว็บเซอร์และความหมายพิเศษหากมี

หากสถานะเริ่มต้นด้วย4nnหรือ5nnคุณต้องการใช้getErrorStream()แทนเพื่ออ่านเนื้อหาการตอบสนองซึ่งอาจมีรายละเอียดข้อผิดพลาด

InputStream error = con.getErrorStream();

โอเคฉันลองแล้วมันส่งคืนสถานะ 404 แต่ที่แปลกคือมันประหยัดใน DB ด้วย! จากที่คุณพูดถึงหมายความว่าบริการ REST ใด ๆ จะส่งคืนเฉพาะรหัสสถานะหรือไม่? จะเกิดอะไรขึ้นหากฉันต้องการส่งคืนข้อมูลเพิ่มเติมเช่นข้อความแสดงข้อผิดพลาดการตรวจสอบ xml หรือ url หากโพสต์สำเร็จ
naiquevin

ใช่ในคำขอแก้ไขเช่น POST / PUT / etc มักจะไม่ส่งคืนร่างกาย โดยปกติคุณต้องการกำหนดสถานะการตอบกลับก่อนที่จะอ่านอินพุตหรือสตรีมข้อผิดพลาด ฉันเพิ่มรายละเอียดบางอย่างในคำตอบ แต่ถ้ามันกลับมาเป็นสถานะ 404 จริงๆอาจมีข้อผิดพลาดบางอย่างในบริการเว็บ ฉันจะรายงานไปยังผู้ดูแล
BalusC

ในกรณีนี้ผู้ดูแลบริการเป็นฉันเอง! .. ผมลองทำ curl โดยใช้ php แล้วมันส่งกลับ 200 (แก้ไขคำถามแล้ว) ลองgetErrorStream()ตามที่แนะนำด้วย มันพ่น NullPointerException new InputStreamReader(con.getErrorStream())บน
naiquevin

ขออภัยฉันไม่คุ้นเคยกับ Spring webservices ฉันได้สัมผัสกับ JAX-WS / RS จาก Java EE 5/6 API มาตรฐานเท่านั้น ฉันขอแนะนำให้ใส่เบรกพอยต์ในวิธีการที่รับผิดชอบในการประมวลผลไฟล์ XML แล้วก้าวต่อไปจากที่นั่น
BalusC

พฤติกรรมนี้ดูเหมือนจะไม่เป็นประโยชน์มากนักโดยเฉพาะอย่างยิ่งเนื่องจากทำให้การอ้างอิงถึงสิ่งต่างๆเป็นURLConnectionปัญหาทั่วไป ฉันสงสัยว่าทำไมพวก Java ถึงไม่ติดตั้งgetInputStream()ในHttpUrlConnectionบรรทัดของreturn responseCode == 200 ? super.getInputStream() : this.getErrorStream(). แต่อย่างไรก็ตาม; คำตอบที่ให้ข้อมูล +1
aroth

51

FileNotFound เป็นเพียงข้อยกเว้นที่โชคร้ายที่ใช้เพื่อระบุว่าเว็บเซิร์ฟเวอร์ส่งคืน 404


1
นั่นไม่ได้อธิบายว่าเหตุใดจึงเพิ่มแถวใน DB ตามที่ OP ระบุ
BalusC

@BalusC: เว้นแต่เซิร์ฟเวอร์จะเพิ่มแถวแล้วส่งคืน 404
Jon Skeet

ใช่ดูเหมือนว่าจะมีพฤติกรรมในลักษณะนี้ หมายความว่าอย่างไร?
naiquevin

@naiquevin: มันยากที่จะพูด แต่เนื่องจากเป็นบริการที่ทำงานในพื้นที่คุณควรจะสามารถแก้ไขข้อบกพร่องได้ด้วยตัวเอง
Jon Skeet

7
HttpURLConnection ยังพ่น FileNotFoundException สำหรับการตอบสนอง 403 (และอาจเป็นอื่น ๆ ) (แม้ว่าร่างกายตอบสนองจะไม่ว่างเปล่าก็ตาม) อย่างไรก็ตามควรตรวจสอบgetResponseCode()ก่อนโทรgetInputStream()เสมอ
Jonik

29

สำหรับทุกคนที่มีปัญหานี้ในอนาคตสาเหตุเป็นเพราะรหัสสถานะคือ 404 (หรือในกรณีของฉันคือ 500) ดูเหมือนว่าInpuStreamฟังก์ชันจะแสดงข้อผิดพลาดเมื่อรหัสสถานะไม่ใช่ 200

ในกรณีของฉันฉันควบคุมเซิร์ฟเวอร์ของตัวเองและส่งคืนรหัสสถานะ 500 เพื่อระบุว่าเกิดข้อผิดพลาด แม้ว่าฉันจะส่งเนื้อหาพร้อมข้อความสตริงที่มีรายละเอียดข้อผิดพลาด แต่ข้อผิดพลาดนั้นinputstreamก็ส่งข้อความโดยไม่คำนึงถึงเนื้อหาที่อ่านได้อย่างสมบูรณ์

หากคุณควบคุมเซิร์ฟเวอร์ของคุณฉันคิดว่าสิ่งนี้สามารถจัดการได้โดยการส่งรหัสสถานะ 200 ตัวเองจากนั้นจัดการสิ่งที่ตอบสนองข้อผิดพลาดของสตริง


21
เพื่อความชัดเจนคุณแค่จัดการมันผิด คุณควรใช้ connection.getResponseCode เพื่อตรวจสอบว่าเรียบร้อยหรือไม่ จากนั้นใช้ connection.getErrorStream เพื่อรับเนื้อหาข้อผิดพลาดแทน getInputStream (หรือคุณสามารถใช้ getResponseMessage) คุณไม่ควรส่งรหัสสถานะ 200 หากเป็นข้อผิดพลาดให้ใช้รหัสข้อผิดพลาด http ตามที่ตั้งใจไว้
rekh127

5

สำหรับใครก็ตามที่สะดุดในเรื่องนี้สิ่งเดียวกันนี้เกิดขึ้นกับฉันขณะพยายามส่งส่วนหัวคำขอ SOAP ไปยังบริการ SOAP ปัญหาคือลำดับที่ไม่ถูกต้องในรหัสฉันขอสตรีมอินพุตก่อนที่จะส่งเนื้อหา XML ในโค้ดด้านล่างบรรทัดจะInputStream in = conn.getInputStream();มาทันทีหลังจากนั้นByteArrayOutputStream out = new ByteArrayOutputStream();คือลำดับสิ่งที่ไม่ถูกต้อง

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 ในกรณีนี้เป็นวิธีที่โชคร้ายในการเข้ารหัสรหัสตอบกลับ HTTP 400


FileNotFound เป็นเพราะการเชื่อมต่อไม่มี uput stream ไม่มีอะไรเกี่ยวข้องกับโค้ดตอบกลับการเข้ารหัส 400 คุณสามารถรับ responsecode ด้วย getResponseCode () ถ้าไม่ใช่ HTTP_OK คุณควรได้รับ body ด้วย conn.getErrorStream () หรือ getResponseMessage ()
rekh127

new ByteArrayOutputStream()ไม่มีส่วนเกี่ยวข้องกับมัน แต่อย่างใด ปัญหาก็คือการสั่งซื้อระหว่างและgetInputStream() getResponseCode()
Marquis of Lorne

4

FileNotFound ในกรณีนี้หมายความว่าคุณได้รับ 404 จากเซิร์ฟเวอร์ของคุณอาจเป็นไปได้ว่าเซิร์ฟเวอร์ไม่ชอบคำขอ "POST"?


แต่จะบันทึกข้อมูลลงในฐานข้อมูล Jaxb2Marshaller อาจเป็นปัญหาที่นี่หรือไม่?
naiquevin

2
สิ่งนี้ไม่ได้เกิดขึ้นสำหรับยุค 404 เท่านั้น นอกจากนี้ยังเกิดขึ้นสำหรับการตอบสนองใด ๆ กับร่างกายที่ว่างเปล่า
Dave Cameron

3
คำตอบนี้น่าเสียดายที่ผิด FileNotFound ในสถานการณ์นี้หมายความว่า HttpURLConnection # getInputStream () เท่านั้นที่ถูกเรียกเมื่อโค้ดตอบกลับสูงกว่า 399 ในขณะที่ในสถานการณ์นี้ควรเรียกใช้ HttpURLConnection # getErrorStream () OTOH ถ้าเซิร์ฟเวอร์ไม่ยอมรับ POST เซิร์ฟเวอร์จะส่งคืน 405 Method Not Allowed ไม่มีความสัมพันธ์กับ FileNotFound ที่ถูกโยนไปที่นั่น
Michal M

0

วิธีแก้ปัญหา:
เพียงแค่เปลี่ยนlocalhostสำหรับIPของพีซีของคุณ
หากคุณต้องการทราบสิ่งนี้: ตัวอย่างWindows + r> cmd> ipconfig
: http: // 192.168.0.107 /directory/service/program.php?action=send บางสิ่ง
เพียงแค่แทนที่192.168 .0.107สำหรับ IP ของคุณเอง (อย่าลอง127.0.0.1เพราะเหมือนกับlocalhost )


-4

กรุณาเปลี่ยน

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

ถึง

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

2
เปลี่ยนทำไม? OP ได้ระบุไว้เป็นพิเศษว่าบริการกำลังทำงานในพื้นที่
Marquis of Lorne

ในกรณีที่คุณต้องการรับทรัพยากรรูปภาพจาก localhost มันไม่ทำงาน
Phuoc Huynh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.