![]() |
Модераторы: LSD, AntonSaburov |
![]() ![]() ![]() |
|
Platon |
|
||||||||||||||||||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1801 Регистрация: 25.4.2006 Репутация: 16 Всего: 40 |
Здравствуйте, уважаемые.
Решил оформить еще 1 фак для сообщества винградовцев. Это некий вводный туториал (tutorial), мануал (manual) или учебное пособие по работе с HttpClient. HttpClient позволяет скачать страницы с интернета с возможностью управлять Cookie и отправлять заголовки на сервер. Преамбула. Недавно, буквально позавчера, мне пришлось столкнуться с проблемой выкачки страницы с сайта. Благо, я слышал о таком магическом инструменте как HttpClient от Apache (Apache как всегда рулит!!!) Его идея была ясна, и не хотелось рыться во всех этих документах, туториалах, примерах. Более того, как и все программисты я хочу всё и сразу и чтоб готовенькое. Начал рыться по винграду. Спасибо LSD по его ответам на форуме я сдвинулся с места. Но не хватало многих мелочей, которые таки заставили меня обратиться к официальным докам, туториалам и примерам. Чтоб уберечь нежные гениальные умы будущих поколений, я решил объединить все эти мелочи в одном месте. И так поехали. Основная часть. Выгружаю сразу код, в котором содержится весь материал.
Засекаем секундомеры! HttpClient можно расценивать как браузер, который не отображает страницу, а только содержит состояние, в котором работает пользователь. Это и все куки, которые устанавливаются в начале сеанса и которыми обменивается с сервером, это и данные авторизации (это оставляю на домашнее задание)
Для меня это были очень важные строчки, с ними я набил много шишек. Первая строчка устанавливает кодировку, в которой будут отправляться строки запроса методом GET и тело запроса методом POST Вторая строчка важна для работы с «выпечкой» Самая подходящая политика для работы с «печенюшками» большинства сайтов это именно CookiePolicy.BROWSER_COMPATIBILITY. Теперь перейдем к самим «печенькам». Браузер всегда находится в каком-то состоянии.
К примеру, пользователь может быть авторизован и при его желании сессия может быть сохранена в cookies. У нас это name и password, гипотетически позволяет работать от имени заранее заведенного аккаунта.
С инициализациией браузера разобрались, пробуем загрузить странички. 1. Методом GET
Всё интуитивно должно быть понятно. О различиях методов GET и POST читать в другом месте. Заострю лишь внимание на двух моментах: 1. Формируемый адрес обладает интересным URLEncoder.encode("Доктор Хаус", SITE_CHARSET) Не то, что бы интересен тут персонаж телесериала, хотя это тоже ^_^, сколько то, что он написан по-русски, а мы знаем, как буржуи дискредитируют нелатиницу, да еще и с проблелом. Все пробелы в адресных строках заменяются на +, а нелатиница заменяется спецстроками типа %FF в результате эта обертка URLEncoder'а поможет нам избавиться от головной боли с переводом в страшный текст: «%C4%EE%EA%F2%EE%F0+%D5%E0%F3%F1» Заметим также, что SITE_CHARSET вносит здесь свою лепту. Строчка выше — это кириллический текст в кодировке windows-1251, в кодировке utf-8 это будет выглядеть так: «%D0%94%D0%BE%D0%BA%D1%82%D0%BE%D1%80+%D0%A5%D0%B0%D1%83%D1%81» Вторая строчка. Я не уверен, что она тут, вообще, действует, так что ее можно проигнорировать. Идем дальше. Пора бы запустить наш запрос.
1-я строчка. Запускаем метод из определенного состояния: на сервер отсылаются все cookies объекта HttpClient, относящиеся к сайту. 2-я строчка. result содержит статус страницы (Мы помним самые известные 200 — страница загружена, 404 — страница не сужествует, 302 — сервер произвел переадресацию) 4-я строчка. выводим извлеченную страничку. getResponseBodyAsString(), от куда же метод знает в какой кодировке страничка? Можно подумать, что мы установили ее с помощью getMethod.getParams().setContentCharset(SITE_CHARSET); Ничего подобного :( Из ответа от сервера, ему передается заголовок Content-Type откуда извлекается кодировка. Если сервер не передаст нам этого заголовка — дело плохо. Об альтернативных способах получения странички чуть позже. 2. Методом POST
Знакомый шаблон? Да. Единственное существенное различие — это метод отправки данных POST. Теперь так лихо все параметры в адресную строку не засунуть. Расстраиваться не стоит у Apache всегда есть чем подсластить программисту жизнь. postMethod.addParameter("name", "Доктор Хаус"); хитрый метод addParameter разберется абсолютно со всеми проблемами сам, нет необходимости в перекодировании кириллического текста. НО, теперь нам важна строчка postMethod.getParams().setContentCharset(SITE_CHARSET);, тело запроса будет кодироваться в установленной кодировке. Здорово! Теперь бонус: Я писал о возможных проблемах метода HttpMethod.getResponseBodyAsString, если сервер не передаст кодировку, в которой написана страница. Альтернативой может послужить самостоятельная обработка сырых байтов переданных данных byte[] HttpMethod.getResponseBody(). Или же для больших документов можно обрабатывать страницу на лету с помощью метода HttpMethod.getResponseBodyAsStream(), если это, конечно, технически возможно. Например, со страницы может передаваться гигантских размеров xml структура, ее можно обрабатывать «на ходу» с помощью SAX Parser'а Или как в нашем случае, не хранить данные, а сразу выдавать их в stdout. Еще 1 важный аспект работы с HttpClient Если в рамках одного экземпляра HttpClient вы работаете последовательно с несколькими объектами HttpMethod К примеру,
В этом кусочке кода обратите внимание на 4 строчку, releaseConnection позволяет закрыть соединение.
Это важный шаг в сторону того, чтобы всё шло так, как оно должно быть. Мы должны сказать HttpClient что мы закончили с соединением и оно может быть переиспользовано. Без таких шагов текущий HttpClient будет ждать неопределенное время, пока соединение освободится, для того, чтобы оно могло быть переиспользовано. А вообще, при работе с HttpClient стоит взять за правило конструкцию
О таймауте Работая с библиотекой, сразу не замечаешь критических моментов, таких как например бесконечное ожидание отклика от сервера. Да и такое бывает, но к счастью в HttpClient предусмотрена и такая функция. Смотрим:
Новшества тут 2-я строчка, которая устанавливает таймаут ожидания ответа, и 4-я строчка, в которой в переменной result хранится информация, о том, что HttpClient не дождался ответа с сервера По умолчанию HttpClient может ждать вечность, так что это нужно учесть. Есть также более тонкая настройка таймаутов для каждого запроса индивидуально, это делается аналогично 2-й строчке, только объект над которым будет совершаться действие - HttpMethod method.getParams().setSoTimeout(TIMEOUT_IN_MILLISECONDS) О SSL Приятно был удивлен, что и с SSL HttpClient благополучно разбирается самостоятельно!!! Т.е. нам не надо искать какие-то сертификаты, что-то шурудить, наворачивать. Согласно гиду по SSL мы можем работать с протоколом SSL также как с обычным незащищенным ^_^ Даже комментировать в коде нечего, один и тот же шаблон.
Послесловие Если бы кто-то до меня написал бы эту тему, я был бы очень рад. Но видимо прошло время потребления, пришло время производства! Принимайте, рецензируйте, пользуйтесь. Да, спонсор статьи мой блог о Java Platon's Java life Это сообщение отредактировал(а) Platon - 13.1.2009, 19:09 |
||||||||||||||||||||||||
|
|||||||||||||||||||||||||
Platon |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1801 Регистрация: 25.4.2006 Репутация: 16 Всего: 40 |
Совсем забыл затронуть тему загрузки файлов на сервер. На форуме есть тема посвященная этому вопросу
|
|||
|
||||
Alenka_ |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 61 Регистрация: 18.6.2007 Репутация: нет Всего: нет |
По поводу того, в какой кодировке сервер присылает ответ-
http://rfc.net/rfc2616.html То есть есть соглашение, что сервер должен использовать кодировку ISO-8859-1, когда не указывает ее в заголовках. Но все ли придерживаются этого соглашения?.. |
|||
|
||||
Shaggie |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 570 Регистрация: 21.12.2006 Где: outer space Репутация: 4 Всего: 72 |
Platon, спасибо!!! Я давненько (признаться, не напрягаясь) искал аналог перлового LWP на Java, и HttpClient в этой роли выглядит как самое то!
|
|||
|
||||
Platon |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1801 Регистрация: 25.4.2006 Репутация: 16 Всего: 40 |
Странно, что никто меня не подправил. Обновил статью. Добавил информацию по поводу HttpMethod#releaseConnection()
|
|||
|
||||
Platon |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1801 Регистрация: 25.4.2006 Репутация: 16 Всего: 40 |
Обновил статью, добавил информацию о таймаутах.
|
|||
|
||||
sith |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 537 Регистрация: 11.2.2007 Репутация: нет Всего: 1 |
... думаю что можешь обновить статью в плане работы с SSL... там все просто... но все же для полной картины...
-------------------- Там где ты ставишь глупые смайлики, я вбиваю восклицания знаки!!! |
|||
|
||||
unkis |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 802 Регистрация: 8.9.2004 Репутация: нет Всего: 1 |
Было бы действительно неплохо написать про SSL
-------------------- www.unkis.com |
|||
|
||||
Platon |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1801 Регистрация: 25.4.2006 Репутация: 16 Всего: 40 |
Эх-эх-эх, я в обычной жизни то с SSL тут не работал, а вы мне предлагаете написать о SSL, ок попробую, разберусь заодно с SSL
|
|||
|
||||
Platon |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1801 Регистрация: 25.4.2006 Репутация: 16 Всего: 40 |
Обновил статью опять о releaseConnection()
|
|||
|
||||
priboltik |
|
||||
Новичок Профиль Группа: Участник Сообщений: 7 Регистрация: 11.11.2007 Репутация: нет Всего: нет |
а почему не написали о том, что делать, если классы не создаются??
например у меня при выполнении даже следующего кода:
выкидывало исключение:
пока не подключил библиотеку commons-logging:Ссылка для скачивания |
||||
|
|||||
Nymph666 |
|
||||||||||
Новичок Профиль Группа: Участник Сообщений: 25 Регистрация: 28.11.2007 Репутация: нет Всего: нет |
Сейчас как раз занимаюсь тем, что пытаюсь получить ответ от Google-поиска через метод Get. Но столкнулась со следующей ошибкой: если напрямую выводить в форму на страницу getMethod.getResponseBodyAsString(), то выдается warning, что Размер стринга слишком большой и рекомендуется использовать getMethod.getResponseBodyAsStream(). Пробую делать это с помощью стрима: Сначала получаю нужный адрес:
Затем обрабатываю результат (Document) следующей функцией, которая как раз должна нам возвращать html-код:
Затем загоняю этот результат в переменную private HTML googleHtml; И вывожу ее с помощью panel от GWT:
Но! Вылезает ошибка The markup in the document preceding the root element must be well-formed. ![]() И черт поймет что не так в этом документе. Возможно кто-то тоже использовал Stream. |
||||||||||
|
|||||||||||
![]() ![]() ![]() |
Правила форума "Java" | |
|
Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Java: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |