Apache HTTPClient выбрасывает java.net.SocketException: сброс соединения для многих доменов - PullRequest
7 голосов
/ 12 марта 2011

Я создаю (хорошо себя ведущий) веб-паук и замечаю, что некоторые серверы заставляют 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

Ответы [ 3 ]

4 голосов
/ 12 марта 2011

Сначала ответим на ваш вопрос:

Сброс соединения вызван проблемой на стороне сервера.Скорее всего, серверу не удалось проанализировать запрос или он не смог обработать его и в результате сбросил соединение, не вернув действительный ответ.Вероятно, в HTTP-запросах, генерируемых HttpClient, есть что-то, что приводит к сбою логики на стороне сервера, возможно, из-за ошибки на стороне сервера.То, что в сообщении об ошибке не указано «по одноранговому узлу», не означает, что на клиентской стороне произошел сброс соединения.

Несколько замечаний:

(1) Несколько популярных сканеров, таких как bixo http://openbixo.org/, используют HttpClient без серьезных проблем, но в значительной степени им пришлось настроить поведение HttpClient, чтобы сделать егоболее снисходительно относится к общим нарушениям протокола HTTP.По умолчанию HttpClient довольно строго относится к соблюдению протокола HTTP.

(2) Почему вы не сообщили о проблеме NPE или любой другой проблеме, с которой вы столкнулись, в проекте HttpClient?

1 голос
/ 27 марта 2013

Эти две настройки иногда помогают:

 client.getParams().setParameter("http.socket.timeout", new Integer(0));
 client.getParams().setParameter("http.connection.stalecheck", new  Boolean(true));

Первый устанавливает время ожидания сокета равным бесконечности.

0 голосов
/ 12 марта 2011

Попробуйте получить трассировку сети, используя wireshark, и увеличьте ее с помощью log4j, регистрирующей HTTPClient.Это должно показать, почему соединение сбрасывается

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...