Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> HttpClient.Как правильно получить content страници 
:(
    Опции темы
unkis
  Дата 14.1.2009, 22:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 802
Регистрация: 8.9.2004

Репутация: нет
Всего: 1



Собственно сабж.

Просто имею вот такой вот код
Код

 private HttpClient initHttpClient() {
        log.debug("Start url is: "+URL);
        HttpClient httpClient = new HttpClient(Controller.getInstance().getConnectionManager());
        httpClient.getParams().setContentCharset(DEFAULT_CHARSET);
        httpClient.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
        httpClient.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
        log.debug("End url is: "+URL);

//            httpClient.getParams().setSoTimeout(ConfigurationParuvendu.TIMEOUT);

        return httpClient;
    }

    public StringBuilder getHTMLPage(String fileName) {
        log.debug("Start");
        int i=0;
        log.trace(i++);
        StringBuilder page = null;
        InputStream responseBody;
        if (URL != null) {
            log.trace(i++);
            HttpClient httpClient = initHttpClient();
            log.trace(i++);
            // Загрузка страницы с запросом методом GET
            GetMethod getMethod = new GetMethod(URL);
            getMethod.getParams().setContentCharset(SITE_CHARSET);
            getMethod.setRequestHeader("User-Agent", USER_AGENT);
            log.trace(i++);
            if (cookies != null) {
                log.trace("Cookie is != null"+(i++));

                //Set cookie
                getMethod.setRequestHeader("Cookie", cookies);
            }
            log.trace(i++);
            try {
                log.trace(i++);
                int result = httpClient.executeMethod(getMethod);
                log.trace("Httpstatus, response code is: :"+result+". for url: "+URL);
                if (result == HttpStatus.SC_OK) {

                    log.trace(i++);
                    // Добовляем страницу в буффер
                    responseBody = getMethod.getResponseBodyAsStream();
                    log.trace(i++);
                    page = new StringBuilder();
                    log.trace(i++);
                    int r = responseBody.read();
                    log.trace("for while "+i++);
                    while (r != -1) {
                        page.append((char) r);
                        r = responseBody.read();
                    }
                    log.trace("behinde while "+i++);
                    responseBody.close();
                    //TODO убрать запись в файл
                    FileWriter f = new FileWriter(fileName + ".html");
                    f.write(page.toString());
                    f.close();
                    log.trace(i++);

                } else {
                    log.warn("Http Error, response code is: " + result+". url is: "+URL);
                    return null;
                }
            } catch (IOException e) {
                log.error("Timeout problem. ", e);
                return null;
            } finally {
                getMethod.releaseConnection();
            }
            log.debug("End");
            return page;
        } else {
            log.warn("Downlad error, url not exist, returned value is null, url is: "+URL);
            return null;
        }

    }


Вот в этом кусочке, зависает один поток, тоесть он не выходит из while.
Код

log.trace("for while "+i++);
   while (r != -1) {
          page.append((char) r);
          r = responseBody.read();
   }
log.trace("behinde while "+i++);


Тоесть иногда бывает так, что r никогда не будет равна -1. 
Что посоветуете и как исправить эту проблему?


--------------------
www.unkis.com
PM MAIL WWW   Вверх
COVD
Дата 14.1.2009, 23:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 11
Всего: 43



Цитата

Тоесть иногда бывает так, что r никогда не будет равна -1. 
Что посоветуете и как исправить эту проблему? 


Если сервер не закрывает свой вывод , то, действительно, никогда и не получите -1. На этом основан серверный push, когда соединение не закрывается, и сервер отправляет данные по мере необходимости. Если же размер "страницы" известен и сервер его указывает в хедере респонса ( поле Content-Length ), то -1 (EOF) должен быть.    

PM MAIL   Вверх
unkis
Дата 15.1.2009, 00:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 802
Регистрация: 8.9.2004

Репутация: нет
Всего: 1



Ну а если размер "страницы" не известен, то как быть?


--------------------
www.unkis.com
PM MAIL WWW   Вверх
COVD
Дата 15.1.2009, 03:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 11
Всего: 43



Если размер серверу заранее не известен, то он может:

1. Или добавить хедер "Connection : close" в респонс, означающий, что концом данных служит закрытие соединения. Это типично для HTTP 1.0 И это не совместимо с keep-alive, т.е. сокетное соединение не может быть повторно использовано для последующих запросов на этот же сервер.

2. Или использовать режим chunked (наиболее вероятно). О чем сервер также должен предупредить клиента, поместив соответствующий хедер в респонс. Это разрешено только в HTTP 1.1, т.е. если клиент прислал запрос в HTTP1.1  и сервер это поддерживает. В этом случае респонс отправляется порциями (chunk) и перед каждым чанком высылается его размер. Конец данных - чанк нулевой длины.   

Чтобы не программировать вручную распознавание конца данных наверное лучше читать строками, а не посимвольно (не из стрима). Я не имел дела с HttpClient, но, думаю, там есть такая возможность.  
  

Это сообщение отредактировал(а) COVD - 15.1.2009, 03:12
PM MAIL   Вверх
Platon
Дата 15.1.2009, 14:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 3
Всего: 40



есть нормальный метод HttpMethod#getResponseBodyAsString();
или я не понял глубины вопроса?

Это сообщение отредактировал(а) Platon - 15.1.2009, 15:05
PM MAIL ICQ   Вверх
unkis
Дата 15.1.2009, 15:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 802
Регистрация: 8.9.2004

Репутация: нет
Всего: 1



Есть такой метод, но почему-то apache не рекомендует его использовать


--------------------
www.unkis.com
PM MAIL WWW   Вверх
Platon
Дата 15.1.2009, 21:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 3
Всего: 40



smile имеете ввиду, что выскакивает warning?

Добавлено через 1 минуту
Цитата

15.01.2009 22:10:35 org.apache.commons.httpclient.HttpMethodBase getResponseBody
WARNING: Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.


Нуу, есть такой момент, но если сервисы не падлят клиентам, то проблем не будет никогда.

Добавлено через 4 минуты и 48 секунд
Можете использовать HttpMethod#getResponseBodyAsString(int maxlen)
PM MAIL ICQ   Вверх
COVD
Дата 15.1.2009, 23:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 11
Всего: 43



Если читать ответ посимвольно, из потока, то надо сначала проверить наличие хедера Transfer-Encoding: chunked ( для HTTP1.1 ). Если он присутствует, то формат для тела ответа такой ( 
http://developers.sun.com/mobility/midp/questions/chunking/ ) :

Цитата

C\r\n
Some data...
11\r\n
Some more data...
0\r\n


В этом примере данные разбиты на два чанка и присутствует чанк нулевой длины в конце, означающий конец данных. 

Размер первого чанка равен 12, что в hex дает C. 
Передается размер чанка ( 3 байта ) :  67 ( это 'С'  ) , 13 ( это '\r'  ) , 10 ( это  '\n' ) 
Потом следуют 12 байт данных  ("Some data...") .

Размер второго чанка равен 17 , что в hex дает 11. 
Передается размер чанка ( 4 байта ) :  49 ( это '1' ), 49 ( это '1' ), 13 ( это '\r'  ) , 10 ( это  '\n' ) 
Потом следуют 17 байт данных  ("Some more data...") .

Конец данных - чанк нулевой длины. Это три байта: 48 (это '0') , 13 ( это '\r'  ) , 10 ( это  '\n' ) 

Соединение сервером не закрывается. Поэтому, надо полагать, никакого -1 получено не будет.

Однако, возможно, есть более простое решение, чем парсить chunked stream. В запросе можно явно указать серверу, что клиент не нуждается в повторном использовании соединения. Для этого служит хедер Connection : close . В этом случае сервер очевидно ( жесткого требования протокол не предьявляет, это следует из здравого смысла ) также предпочтет закрытие соединения после окончания данных. И в этом случае ("If the server chooses to close the connection immediately after sending the response") сервер обязан также указать хедер Connection : close . 

Таким образом, если посылать запросы с хедером Connection : close , то с большой вероятностью сервер не будет использовать "chunked", а будет отвечать аналогичным хедером и закрывать соединение после отсылки ответа. И -1 будет срабатывать.

Или еще один способ - использовать протокол HTTP1.0 . В нем режим "chunked" вообще не предусмотрен и концом данных служит разрыв соединения.





Это сообщение отредактировал(а) COVD - 16.1.2009, 06:39
PM MAIL   Вверх
unkis
Дата 19.1.2009, 19:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 802
Регистрация: 8.9.2004

Репутация: нет
Всего: 1



Спасибо, если я правильно всё понял, то я могу указываю каким протоколом я хочу пользоваться, так?
А если сервер не поддерживает этот протокол?


--------------------
www.unkis.com
PM MAIL WWW   Вверх
COVD
Дата 20.1.2009, 18:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 11
Всего: 43



Сервер, если стандартный, то поддержит 1.0 . А вот существующие клиенты похоже не позволяют менять версию протокола. 

Можно отправку запроса и чтение ответа вручную программировать. Где-то на форуме такие примеры были. 
Что-то вроде такого:

Код

            Socket socket = new Socket("127.0.0.1", 80);

            BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            wr.write("GET /index.jsp HTTP/1.0\r\n");
            wr.write("Host: 127.0.0.1\r\n");
            wr.write("Content-Type: text/html\r\n");
            wr.write("\r\n");
            wr.flush();

            BufferedReader rd = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String response = null;

            while ((response = rd.readLine()) != null) {
                System.out.println("response:" + response);            
            }


Вы можете послать на сервер HTTP/1.0 или HTTP/1.1 в первой строке.

Но все же лучше в стандартном клиенте попробовать поставить хедер Connection : close.

Это сообщение отредактировал(а) COVD - 20.1.2009, 18:38
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Работа с сетью | Следующая тема »


 




[ Время генерации скрипта: 0.0516 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.