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. Это должно показать, почему соединение сбрасывается