HttpURLConnectionからInputStreamオブジェクトを取得中にFileNotFoundException


109

(JavaでcUrlを使用するために)HttpURLConnectionを使用してURLに投稿リクエストを送信しようとしています。リクエストのコンテンツは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フレームワークとJaxb2Marshallerを使用して応答XMLを作成します。

クラスReadWriteTextFileはここから取得されます

ありがとう。

編集: まあそれはデータベースにデータを保存し、同時に404応答ステータスコードを送り返します。

また、phpを使用してcurlを実行し、結果CURLINFO_HTTP_CODEが200になることを印刷してみました。

これをデバッグするにはどうすればいいですか?サービスとクライアントの両方がローカルサーバー上にあります。

解決済み: SO自体の回答 を参照した後、問題を解決できました。

標準ポート以外のURLに接続すると、HttpURLConnectionが常に404応答を返すようです。

これらの行を追加すると解決しました

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

1
「ターミナルからこのコードを実行するとき」-どのコード?何が機能しているか、何が機能していないかは不明です。
Jon Skeet、2011年

HttpCurlは、このメインメソッドを持つクラスの名前です。このクラスはコンパイルされ、ターミナルから実行されます
naiquevin

3
私は同じ問題を経験しましたが、ここでの解決策はどれもうまくいきませんでした。私はそれがJava 1.7.0_05の問題であることを最終的に理解し、最新バージョン1.7.0_21に更新し、問題は解消しました。この問題はJava 1.6では発生しないことにも気付きました。まだ行き詰まっている人のための参考までに。
Steven

みんな!回答ではなく、質問に対する「解決済み」のコメントを参照してください。
김준호2015年

回答:


130

Spring / JAXBの組み合わせはわかりませんが、平均的なREST WebサービスはPOST / PUTで応答本文を返さず、応答ステータスのみを返します。体の代わりにそれを決定したいと思います。

交換する

InputStream response = con.getInputStream();

沿って

int status = con.getResponseCode();

利用可能なすべてのステータスコードとその意味は、前にリンクしたように、HTTP仕様で利用できます。Webサービス自体には、Webサービスでサポートされているすべてのステータスコードと、もしあればそれらの特別な意味の概要を説明したドキュメントも付属しています。

ステータスが4nnまたは5nnで始まる場合は、getErrorStream()代わりにを使用して、エラーの詳細が含まれている可能性のあるレスポンスの本文を読み取ります。

InputStream error = con.getErrorStream();

OK、これを試してみるとステータス404が返されます。しかし、奇妙なことに、DBにも保存されます!また、あなたが言ったことから、RESTサービスはステータスコードのみを返すことを意味しますか?投稿が成功した場合、xml検証エラーメッセージやURLなどの詳細情報を返したい場合はどうすればよいですか?
naiquevin

はい、POST / PUT / etcなどの変更リクエストでは、通常、ボディは返されません。通常、入力またはエラーストリームを読み取る前に、応答ステータスを確認します。私は答えにいくつかの詳細を追加しました。しかし、それが実際にステータス404を返す場合は、おそらくWebサービスにいくつかのバグがあります。メンテナに報告します。
BalusC 2011年

この場合、サービスのメンテナーはたまたま私です!..まあ、phpを使用してcurlを実行しようとすると、200が返されます(私の質問を編集しました)getErrorStream()。でNullPointerExceptionをスローしnew InputStreamReader(con.getErrorStream())ます。
naiquevin

申し訳ありませんが、私はSpring Webサービスに慣れていません。私は、標準のJava EE 5/6 APIからのJAX-WS / RSの実務経験しかありません。XMLファイルの処理を担当するメソッドにブレークポイントを設定し、そこからさらに先に進むことをお勧めします。
BalusC 2011年

この動作は非常に役に立たないように見えます。特に、より一般的なURLConnection問題によって物事を参照するためです。なぜJavaの連中が単にgetInputStream()HttpUrlConnection沿って実装しなかったのかしらreturn responseCode == 200 ? super.getInputStream() : this.getErrorStream()。しかしとにかく; 有益な答え、+ 1。
2013

51

FileNotFound は、Webサーバーが404を返したことを示すために使用される、残念な例外です。


1
これは、OPで述べられているように行がDBに追加される理由を説明していません。
BalusC 2011年

@BalusC:サーバは、行を追加しない限り、次に 404返す
ジョンスキート

はい、このように動作しているようです。どういう意味ですか ?
naiquevin

@naiquevin:言うのは難しいですが、ローカルで実行されているサービスであることを考えると、自分でデバッグできるはずです。
Jon Skeet

7
HttpURLConnectionは、403応答(およびおそらく他の応答)に対してFileNotFoundExceptionもスローします。(応答の本文が空でなくても、そうです。)とにかく、getResponseCode()呼び出す前に必ず調査してくださいgetInputStream()
Jonik 2013年

29

将来この問題が発生する人にとっては、ステータスコードが404(または私の場合は500)だったことが原因です。それが表示されますInpuStreamステータスコードが200でない場合関数はエラーをスローするようです。

私の場合、自分のサーバーを制御していて、エラーが発生したことを示す500ステータスコードを返していました。エラーの詳細を示す文字列メッセージを含む本文も送信しましたinputstreamが、本文が完全に読み取り可能であるかどうかに関係なく、エラーをスローしました。

サーバーを制御している場合は、200のステータスコードを自分に送信し、文字列エラーの応答を処理することでこれを処理できると思います。


21
明確にするために、あなたはそれを間違って扱っているだけです。connection.getResponseCodeを使用して、問題がないかどうかを確認する必要があります。次に、getInputStreamの代わりにconnection.getErrorStreamを使用してエラー本文を取得します。(または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ストリームがないために発生しました。応答コード400のエンコードとは関係ありません。応答コードはgetResponseCode()で取得できます。次に、HTTP_OKでない場合は、conn.getErrorStream()またはgetResponseMessage()でボディを取得する必要があります
rekh127

new ByteArrayOutputStream()それとは何の関係もありません。問題は、間などの順序であるgetInputStream()getResponseCode()
ローン侯爵

4

この場合のFileNotFoundは、サーバーから404を取得したことを意味します。サーバーが「POST」リクエストを嫌う可能性がありますか?


ただし、レコードはデータベースに保存されます。ここでJaxb2Marshallerが問題になるでしょうか?
naiquevin

2
これは404でのみ発生するわけではありません。ボディが空の応答でも発生します。
デイブキャメロン

3
残念ながらこの答えは間違っています。この状況でのFileNotFoundは、応答コードが399を超えたときにHttpURLConnection#getInputStream()が呼び出されたことだけを意味しましたが、この状況ではHttpURLConnection#getErrorStream()が呼び出されているはずです。OTOH、サーバーがPOSTを受け入れない場合は、405 Method Not Allowedを返します。そこにFileNotFoundがスローされるのとは関係ありません。
Michal M

0

解決策: これを知りたい場合は、PC のIPlocalhost
変更してください :Windows + r> cmd> ipconfigの 例:http:// 192.168.0.107 /directory/service/program.php?action=sendSomethingを 192.168に 置き換えます独自のIPの場合は.0.107localhostと同じであるため、127.0.0.1は試さないでください)



-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は、サービスがローカルで実行されていると具体的に述べています。
ローン侯爵

ローカルホストから画像リソースを取得する必要がある場合、機能しません。
Phuoc Huynh 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.