Apache HTTPClient бросает java.сеть.SocketException: сброс соединения для многих доменов

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

  • кажется, что ошибка не вызвана удаленной машиной, потому что исключение не говорит "равным"

  • это переполнение стека кажется relavent java.сеть.SocketException: сброс соединения но ответы не показывают, почему это произойдет только с HTTP-клиентом Apache, а не с другим подходы.

бонусный вопрос: я делаю изрядное количество обхода с этой системой. Есть ли вообще лучший класс Java для этого, кроме HTTP-клиента Apache? Я нашел ряд проблем (таких как исключение NullPointerException, которое я должен поймать в коде выше). Кажется, что HTTPClient очень придирчив к серверным коммуникациям - более придирчив, чем я хотел бы для искателя, который не может просто сломаться, когда сервер не ведет себя.

спасибо всем!

решение

честно говоря, у меня нет идеального решения, но оно работает, так что для меня этого достаточно.

как отметил Олег ниже, Bixo создал искатель, который настраивает HttpClient, чтобы быть более снисходительным к серверам. Чтобы "обойти" проблему больше, чем исправить ее, я просто использовал SimpleHttpFetcher, предоставленный Bixo здесь: (ссылка удалена-так думает, что я спамер, поэтому вам придется самому google)

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

Спасибо за помощь всем.

изменить: TinyBixo

Привет всем. Итак, мне понравилось, как работал Bixo, но мне не понравилось, что у него было так много зависимостей (включая все Hadoop). Итак, я создал значительно упрощенный Bixo без всех зависимостей. Если вы столкнулись с проблемами выше, я бы рекомендовал использовать его (и не стесняйтесь делать запросы на вытягивание, если вы хотите его обновить!)

это здесь: https://github.com/juliuss/TinyBixo

3 ответов


во-первых, чтобы ответить на ваш вопрос:

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

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

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

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


эти два параметра иногда поможет:

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

первый устанавливает тайм-аут сокета бесконечным.


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