FileNotFoundException, отримуючи об'єкт InputStream з HttpURLConnection


109

Я намагаюся надіслати запит на пошту до URL за допомогою HttpURLConnection (для використання cUrl в Java). Вміст запиту становить xml, і в кінцевій точці додаток обробляє xml і зберігає запис у базу даних, а потім надсилає відповідь у вигляді рядка xml. Додаток розміщено на апаш-томкаті локально.

Коли я виконую цей код з терміналу, до db додається рядок, як очікувалося. Але виняток видається наступним чином під час отримання 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 безпосередньо, це виняток не кидає.

Додаток служби використовує весняний фреймворк та Jaxb2Marshaller для створення відповіді xml.

Клас ReadWriteTextFile взято звідси

Дякую.

Редагувати: Добре це зберігає дані в БД і одночасно надсилає код статусу відповіді 404.

Я також спробував зробити завиток за допомогою php і роздрукувати, CURLINFO_HTTP_CODEякий виявляється 200.

Будь-які ідеї щодо того, як мені зайнятися налагодженням цього? І сервіс, і клієнт перебувають на локальному сервері.

Вирішено: Я міг би вирішити проблему, звернувшись до відповіді на САМ.

Здається, HttpURLConnection завжди повертає відповідь 404 під час підключення до URL з нестандартним портом.

Додавання цих рядків вирішило це

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

1
"Коли я виконую цей код з терміналу" - який код? Незрозуміло, що працює проти того, що не працює.
Джон Скіт

HttpCurl - ім'я класу, у якого є цей основний метод. Цей клас складається і працює з терміналу
naiquevin

3
У мене виникло те саме питання, але жодне з рішень тут не спрацювало. Зрештою я зрозумів, що це проблема з Java 1.7.0_05 та оновлений до останньої версії 1.7.0_21, і проблема пішла. Я також зрозумів, що проблема не виникає в Java 1.6. Просто FYI для тих, хто ще застряг.
Стівен

Хлопці! див. "Вирішений" коментар до питання, а не відповіді!
김준호

Відповіді:


130

Я не знаю про вашу комбінацію Spring / JAXB, але середня веб-служба REST не поверне тіло відповідей на POST / PUT, а лише статус відповіді . Ви б хотіли визначити це замість тіла.

Замініть

InputStream response = con.getInputStream();

по

int status = con.getResponseCode();

Усі доступні коди статусу та їх значення доступні у специфікації HTTP, як це було пов'язано раніше. Сам веб-сервіс також повинен містити деяку документацію, в якій переглядаються всі коди статусу, підтримувані веб-сервісом, та їх особливе значення, якщо вони є.

Якщо стан починається з 4nnабо 5nn, ви хочете використовувати getErrorStream()замість цього, щоб прочитати орган відповіді, який може містити дані про помилку.

InputStream error = con.getErrorStream();

Добре, я спробував це, і він повертає статус 404. Але як не дивно, це також економія в БД! Також з того, що ви згадуєте, чи означає це, що будь-яка служба REST поверне лише код статусу? Що робити, якщо я хочу повернути назад додаткову інформацію, таку як повідомлення про помилку перевірки XML чи URL-адресу, якщо публікація успішна?
naiquevin

Так, для запитів на модифікацію, таких як POST / PUT / тощо, це зазвичай не повертає тіло. Зазвичай ви хочете визначити статус відповіді перед читанням потоку введення чи помилки. Я доклав трохи детальних відповідей. Але якщо він дійсно повертає статус 404, то, ймовірно, є помилка у веб-службі. Я б доповів своєму технічному обслуговувачу.
BalusC

У такому випадку мене обслуговує сервіс! .. Ну я спробував зробити завиток за допомогою php, і він повертає 200 (відредагував моє запитання) Також спробував, getErrorStream()як пропонується. Він кидає NullPointerException на new InputStreamReader(con.getErrorStream()).
naiquevin

Вибачте, я не знайомий з весняними веб-сервісами. Я маю лише досвід роботи з JAX-WS / RS зі стандартного API Java EE 5/6. Я б запропонував поставити точку перерви на метод, відповідальний за обробку файлу XML, а потім піти далі звідти.
BalusC

Така поведінка видається дуже не корисною, тим більше, що вона робить посилання на речі більш загальними URLConnectionпроблемами. Цікаво, чому хлопці з Java не просто реалізували це getInputStream()в HttpUrlConnectionрамках return responseCode == 200 ? super.getInputStream() : this.getErrorStream(). Але все одно; інформативна відповідь, +1.
aroth

51

FileNotFound - лише прикрий виняток, який використовується для вказівки на те, що веб-сервер повернув номер 404.


1
Це не пояснює, чому рядок додається до БД, як заявлено ОП.
BalusC

@BalusC: Якщо сервер не додасть рядок, а потім поверне 404.
Джон Скіт,

так, здається, що він веде себе таким чином. Що це означає ?
naiquevin

@naiquevin: Важко сказати, але враховуючи, що це служба, яка працює локально, ви повинні мати можливість налагодити її самостійно.
Джон Скіт

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 стався тому, що в з'єднанні немає потоку інструкцій. Це не мало нічого спільного з кодуванням відповіді кодом 400. Відповідь ви можете отримати за допомогою getResponseCode (). Тоді якщо це не HTTP_OK, ви повинні отримати тіло conn.getErrorStream () або getResponseMessage ()
rekh127

new ByteArrayOutputStream()не має нічого спільного з цим. Питання полягає в порядку між getInputStream()і до getResponseCode().
Маркіз Лорн

4

FileNotFound в цьому випадку означає, що ви отримали 404 від свого сервера - може, сервер не любить "POST" запити?


Але це зберігає запис у db. Може тут проблема Jaxb2Marshaller?
naiquevin

2
Це відбувається не лише 404-х. Це трапляється і для будь-якої відповіді з порожнім тілом.
Дейв Кемерон

3
Ця відповідь, на жаль, неправильна. FileNotFound у цій ситуації означав лише те, що HttpURLConnection # getInputStream () викликався, коли код відповіді був вище 399, тоді як у цій ситуації HttpURLConnection # getErrorStream () повинен був викликатися. OTOH, якщо сервер не прийме POST, він поверне метод 405 не дозволений. Немає відношення до того, що 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
Чому це змінити ? ОП спеціально заявила, що служба працює на місцях.
Маркіз Лорн

Якщо вам потрібно отримати ресурс зображення від localhost, він не працює.
Phuoc Huynh
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.