Я создаю (хорошо себя ведущий) веб-паук и замечаю, что некоторые серверы заставляют Apache HttpClient выдавать мне SocketException, а именно:
java.net.SocketException: Connection reset
Код, который вызывает это:
// Execute the request
HttpResponse response;
try {
response = httpclient.execute(httpget); //httpclient is of type HttpClient
} catch (NullPointerException e) {
return;//deep down in apache http sometimes throws a null pointer...
}
Для большинства серверов это просто отлично. Но для других он сразу вызывает исключение SocketException.
Пример сайта, который вызывает немедленное исключение SocketException: http://www.bhphotovideo.com/
Отлично работает (как и большинство веб-сайтов): http://www.google.com/
Теперь, как вы можете видеть, www.bhphotovideo.com нормально загружается в веб-браузер. Он также прекрасно загружается, когда я не использую HTTP-клиент Apache. (Код такой:)
HttpURLConnection c = (HttpURLConnection)url.openConnection();
BufferedInputStream in = new BufferedInputStream(c.getInputStream());
Reader r = new InputStreamReader(in);
int i;
while ((i = r.read()) != -1) {
source.append((char) i);
}
Итак, почему бы мне просто не использовать этот код? Ну, есть некоторые ключевые функции в HTTP-клиенте Apache, которые мне нужно использовать.
Кто-нибудь знает, почему некоторые серверы вызывают это исключение?
Исследования пока:
Проблема возникает на моих локальных компьютерах Mac и экземпляре AWS EC2, поэтому это не локальный брандмауэр.
Кажется, ошибка не вызвана удаленной машиной, потому что исключение не говорит "peer"
Это переполнение стека кажется относительным java.net.SocketException: сброс подключения , но ответы не показывают, почему это произойдет только с HTTP-клиентом Apache, а не другими подходами.
Бонусный вопрос: я довольно много ползаю по этой системе. Есть ли вообще лучший Java-класс для этого, кроме Apache HTTP Client? Я обнаружил ряд проблем (например, исключение NullPointerException, которое я должен уловить в приведенном выше коде). Кажется, что HTTPClient очень требователен к взаимодействию с сервером - более требователен, чем я хотел бы для сканера, который не может просто сломаться, когда сервер не ведет себя.
Спасибо всем!
Решение
Честно говоря, у меня нет идеального решения, но оно работает, так что мне этого достаточно.
Как указывает oleg ниже, Bixo создал сканер, который настраивает HttpClient для большей простоты для серверов. Чтобы «обойти» проблему больше, чем исправить, я просто использовал SimpleHttpFetcher, предоставленный Bixo здесь:
(ссылка удалена - ТАК думает, что я спамер, так что вам придется гуглить сам)
SimpleHttpFetcher fetch = new SimpleHttpFetcher(new UserAgent("botname","contact@yourcompany.com","ENTER URL"));
try {
FetchedResult result = fetch.fetch("ENTER URL");
System.out.println(new String(result.getContent()));
} catch (BaseFetchException e) {
e.printStackTrace();
}
Недостатком этого решения является то, что для Bixo существует множество зависимостей, поэтому это может быть не лучшим решением для всех. Тем не менее, вы всегда можете просто работать с использованием DefaultHttpClient и посмотреть, как они его создали, чтобы заставить его работать. Я решил использовать весь класс, потому что он обрабатывает некоторые вещи для меня, такие как автоматическое отслеживание перенаправления (и сообщение окончательного адреса назначения), которые полезны.
Спасибо за помощь всем.
Редактировать: TinyBixo
Привет всем. Итак, мне понравилось, как работает Bixo, но не понравилось, что в нем так много зависимостей (включая весь Hadoop). Итак, я создал значительно упрощенный Bixo безо всяких зависимостей. Если вы столкнулись с проблемами, описанными выше, я бы порекомендовал использовать их (и не стесняйтесь делать пул-запросы, если вы хотите обновить его!)
Доступно здесь: https://github.com/juliuss/TinyBixo