HttpURLConnection'dan InputStream nesnesini alırken FileNotFoundException


109

HttpURLConnection kullanarak (java'da cUrl kullanmak için) bir url'ye gönderi isteği göndermeye çalışıyorum. İsteğin içeriği xml'dir ve son noktada, uygulama xml'yi işler ve veritabanına bir kayıt saklar ve ardından xml dizesi biçiminde bir yanıt gönderir. Uygulama yerel olarak apache-tomcat üzerinde barındırılmaktadır.

Bu kodu terminalden çalıştırdığımda, beklendiği gibi db'ye bir satır ekleniyor. Ancak, InputStream'i bağlantıdan alırken aşağıdaki gibi bir istisna atılır

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)

İşte kod

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

Kafa karıştırıcı çünkü istisna satıra kadar izleniyor InputStream response = con.getInputStream();ve FileNotFoundException için herhangi bir dosya yok gibi görünüyor.

Doğrudan bir xml dosyasına bağlantı açmaya çalıştığımda, bu istisnayı atmıyor.

Servis uygulaması, yanıt xml'sini oluşturmak için yay çerçevesini ve Jaxb2Marshaller'ı kullanır.

ReadWriteTextFile sınıfı buradan alınır.

Teşekkürler.

Düzenleme: Verileri DB'ye kaydeder ve aynı zamanda 404 yanıt durum kodunu geri gönderir.

Ayrıca php kullanarak bir curl yapmayı denedim ve CURLINFO_HTTP_CODEhangisinin 200 olduğu ortaya çıktı.

Bu hatayı nasıl ayıklayacağım hakkında bir fikriniz var mı? Hem hizmet hem de istemci yerel sunucudadır.

Çözüldü: SO ile ilgili bir cevaba atıfta bulunduktan sonra sorunu çözebilirim .

HttpURLConnection, standart olmayan bir bağlantı noktasına sahip bir url'ye bağlanırken her zaman 404 yanıtı döndürüyor gibi görünüyor.

Bu satırları eklemek sorunu çözdü

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

1
"Bu kodu terminalden çalıştırdığımda" - hangi kod? Neyin işe yaradığı ve neyin çalışmadığı belirsiz.
Jon Skeet

HttpCurl, bu ana yönteme sahip sınıfın adıdır. Bu sınıf terminalden derlenir ve çalıştırılır
naiquevin

3
Aynı sorunu yaşadım, ancak buradaki çözümlerin hiçbiri işe yaramadı. Sonunda Java 1.7.0_05 ile ilgili bir sorun olduğunu anladım ve en son sürüm 1.7.0_21'e güncelledim ve sorun ortadan kalktı. Java 1.6'da da sorunun oluşmadığını fark ettim. Hala sıkışmış olan herkes için bir FYI.
Steven

Beyler! cevaplar yerine soru için "Çözüldü" yorumuna bakın!
김준호

Yanıtlar:


130

Spring / JAXB kombinasyonunuzu bilmiyorum, ancak ortalama REST web hizmeti POST / PUT'ta bir yanıt gövdesi döndürmeyecek, yalnızca bir yanıt durumu . Vücut yerine onu belirlemek istersiniz.

Değiştir

InputStream response = con.getInputStream();

tarafından

int status = con.getResponseCode();

Mevcut tüm durum kodları ve anlamları, daha önce bağlantılı olduğu gibi HTTP spesifikasyonunda mevcuttur. Web hizmetinin kendisi, web hizmeti tarafından desteklenen tüm durum kodlarını ve varsa özel anlamlarını gözden geçiren bazı belgelerle birlikte gelmelidir.

Durum 4nnveya ile başlıyorsa 5nn, getErrorStream()bunun yerine hata ayrıntılarını içerebilecek yanıt gövdesini okumak için kullanmak istersiniz .

InputStream error = con.getErrorStream();

Tamam bunu denedim ve 404 durumunu döndürdü. Ama tuhaf bir şekilde, aynı zamanda DB'de de tasarruf ediyor! Ayrıca bahsettiğinizden, herhangi bir REST hizmetinin yalnızca bir durum kodu döndüreceği anlamına mı geliyor? Bir xml doğrulama hata iletisi veya gönderi başarılı olursa bir url gibi daha fazla bilgiyi geri döndürmek istersem ne olur?
naiquevin

Evet, POST / PUT / vb. Gibi değişiklik taleplerinde genellikle bir gövde döndürmez. Genellikle girişi veya hata akışını okumadan önce yanıt durumunu belirlemek istersiniz. Cevaba biraz detay ekledim. Ama gerçekten 404 durumunu döndürüyorsa, muhtemelen web hizmetinde bazı hatalar vardır. Bakıcısına rapor verirdim.
BalusC

Bu durumda hizmetin sorumlusu ben oluyorum! .. php kullanarak curl yapmayı denedim ve 200 döndürüyor (sorumu düzenledim) Ayrıca getErrorStream()önerildiği gibi denedim . Bir NullPointerException oluşturur new InputStreamReader(con.getErrorStream()).
naiquevin

Üzgünüm, Spring web hizmetlerine aşina değilim. Ben sadece standart Java EE 5/6 API'den JAX-WS / RS ile deneyime sahibim. XML dosyasını işlemekten sorumlu yönteme bir kesme noktası koymanızı ve ardından oradan daha ileri bir adım atmanızı öneririm.
BalusC

Bu davranış, özellikle şeylere daha genel URLConnectionsorunlu olarak atıfta bulunulmasını sağladığından, çok kullanışlı görünmüyor . Java adamlar sadece uygulamıyor Acaba neden getInputStream()içinde HttpUrlConnectionçizgisinde return responseCode == 200 ? super.getInputStream() : this.getErrorStream(). Ama yine de; bilgilendirici cevap, +1.
aroth

51

FileNotFound sadece web sunucusunun bir 404 döndürdüğünü belirtmek için kullanılan talihsiz bir istisnadır.


1
Bu, OP tarafından belirtildiği gibi satırın neden DB'ye eklendiğini açıklamıyor.
BalusC

@BalusC: Sunucu bir satır ekleyip sonra bir 404 döndürmediği sürece .
Jon Skeet

evet bu şekilde davranıyor gibi görünüyor. Bu ne demek ?
naiquevin

@naiquevin: Söylemesi zor, ancak yerel olarak çalışan bir hizmet olduğu göz önüne alındığında, kendi kendinize hata ayıklayabilmelisiniz.
Jon Skeet

7
HttpURLConnection ayrıca 403 yanıt (ve muhtemelen diğerleri) için FileNotFoundException oluşturur. (Tepki organıdır bile değil boş, öyle görünüyor.) Neyse, her zaman araştırmak getResponseCode()çağırmadan önce getInputStream().
Jonik

29

Gelecekte bu sorunu yaşayan herkes için bunun nedeni, durum kodunun 404 olmasıdır (veya benim durumumda 500 idi). InpuStreamDurum kodu 200 olmadığında işlevin bir hata atacağı görülüyor .

Benim durumumda kendi sunucumu kontrol ediyorum ve bir hata oluştuğunu belirtmek için 500 durum kodunu döndürüyordum. Hatayı detaylandıran bir dizeli mesaj içeren bir gövde göndermeme rağmen inputstream, vücut tamamen okunabilir olsa da bir hata attı.

Sunucunuzu kontrol ediyorsanız, bunun kendinize bir 200 durum kodu göndererek ve ardından dize hatası yanıtı ne olursa olsun işlenerek halledilebileceğini düşünüyorum.


21
Açık olmak gerekirse, sadece yanlış idare ediyorsunuz. Doğru olup olmadığını kontrol etmek için connection.getResponseCode'u kullanmalısınız. Daha sonra getInputStream yerine hata gövdesini almak için connection.getErrorStream kullanın. (veya getResponseMessage'ı kullanabilirsiniz) Hata ise 200 durum kodu göndermemelisiniz, http hata kodlarını amaçlandığı gibi kullanın.
rekh127

5

Bu konuda tökezleyen başka biri için, aynısı bir SOAP servisine bir SOAP istek başlığı göndermeye çalışırken bana da oldu. Sorun kodda yanlış bir sıraydı, XML gövdesini göndermeden önce giriş akışını istedim. Aşağıdaki kodda, satır InputStream in = conn.getInputStream();hemen ardından geldi ByteArrayOutputStream out = new ByteArrayOutputStream();, bu da yanlış bir sıra.

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 bu durumda, HTTP yanıt kodu 400'ü kodlamanın talihsiz bir yoluydu.


FileNotFound, bağlantının bir uput akışına sahip olmamasıydı. Yanıt kodunun kodlanmasıyla ilgisi yoktur. Yanıt kodunu getResponseCode () ile alabilirsiniz. O zaman HTTP_OK değilse, gövdeyi conn.getErrorStream () veya getResponseMessage () ile almalısınız
rekh127

new ByteArrayOutputStream()bununla hiçbir ilgisi yok. Sorun arasında olduğu sırasıdır getInputStream()ve getResponseCode().
Lorne Markisi

4

Bu durumda FileNotFound, sunucunuzdan bir 404 aldığınız anlamına gelir - sunucu "POST" isteklerini beğenmiyor olabilir mi?


Ancak db'ye bir kayıt kaydediyor. Jaxb2Marshaller buradaki sorun olabilir mi?
naiquevin

2
Bu sadece 404'lerde olmuyor. Aynı zamanda boş gövdeli herhangi bir yanıt için de olur.
Dave Cameron

3
Bu cevap maalesef yanlış. Bu durumda FileNotFound, yalnızca yanıt kodu 399'un üzerindeyken HttpURLConnection # getInputStream () çağrıldığı anlamına gelirken, bu durumda HttpURLConnection # getErrorStream () çağrılmalıdır. OTOH, sunucu POST'ları kabul etmezse, 405 Yönteme İzin Verilmiyor döndürürdü. FileNotFound'un oraya atılmasıyla bir ilişkisi yok.
Michal M

0

Çözüm:
Sadece değişim localhost için IP PC'nizin
bunu bilmek istiyorsanız: Windows + r> cmd> ipconfig
örnek: http: // 192.168.0.107 /directory/service/program.php?action=sendSomething
sadece yerine 192.168 .0.107 kendi IP'niz için ( 127.0.0.1'i denemeyin çünkü localhost ile aynıdır )


-4

Lütfen değiştir

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

İçin

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

2
Neden değiştirdin ? OP, hizmetin yerel olarak çalıştığını özellikle belirtmiştir.
Lorne Markisi

Localhost'tan görüntü kaynağına ihtiyacınız olması durumunda çalışmaz.
Phuoc Huynh
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.