Java HttpClient, кажется, кеширует контент - PullRequest
4 голосов
/ 10 марта 2012

Я создаю простой веб-скребок, и мне нужно выбрать одну и ту же страницу несколько сотен раз, и на странице есть атрибут, который является динамическим и должен меняться при каждом запросе. Я создал многопоточный класс на основе HttpClient для обработки запросов, и я использую ExecutorService для создания пула потоков и запуска потоков. Проблема в том, что динамический атрибут иногда не меняется при каждом запросе, и в итоге я получаю одно и то же значение в 3 или 4 последующих потоках. Я много читал о HttpClient, и я действительно не могу найти, откуда эта проблема. Это может быть что-то о кешировании или что-то подобное!?

Обновление: вот код, выполняемый в каждом потоке:

HttpContext localContext = new BasicHttpContext();

HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params,
        HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);

ClientConnectionManager connman = new ThreadSafeClientConnManager();

DefaultHttpClient httpclient = new DefaultHttpClient(connman, params);

HttpHost proxy = new HttpHost(inc_proxy, Integer.valueOf(inc_port));
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
        proxy);

HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("User-Agent",
        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");

String iden = null;
int timeoutConnection = 10000;
HttpConnectionParams.setConnectionTimeout(httpGet.getParams(),
        timeoutConnection);

try {

    HttpResponse response = httpclient.execute(httpGet, localContext);

    HttpEntity entity = response.getEntity();

    if (entity != null) {

        InputStream instream = entity.getContent();
        String result = convertStreamToString(instream);
        // System.out.printf("Resultado\n %s",result +"\n");
        instream.close();

        iden = StringUtils
                .substringBetween(result,
                        "<input name=\"iden\" value=\"",
                        "\" type=\"hidden\"/>");
        System.out.printf("IDEN:%s\n", iden);
        EntityUtils.consume(entity);
    }

}

catch (ClientProtocolException e) {
    // TODO Auto-generated catch block
    System.out.println("Excepção CP");

} catch (IOException e) {
    // TODO Auto-generated catch block
    System.out.println("Excepção IO");
}

Ответы [ 3 ]

4 голосов
/ 10 марта 2012

HTTPClient не использует кеш по умолчанию (при использовании только класса DefaultHttpClient).Это происходит, если вы используете CachingHttpClient, который является HttpClient интерфейсным декоратором, включающим кэширование:

HttpClient client = new CachingHttpClient(new DefaultHttpClient(), cacheConfiguration);

Затем он анализирует заголовки If-Modified-Since и If-None-Match, чтобы решить, будет ли запрос удаленномусервер выполняется, или если его результат возвращается из кэша.

Я подозреваю, что ваша проблема вызвана тем, что прокси-сервер стоит между вашим приложением и удаленным сервером.

Вы можете легко проверить это с приложением curl;выполнить некоторое количество запросов без пропуска прокси:

#!/bin/bash

for i in {1..50}
do
  echo "*** Performing request number $i"
  curl -D - http://yourserveraddress.com -o $i -s
done

А затем выполнить diff между всеми загруженными файлами.Все они должны иметь различия, которые вы упомянули.Затем добавьте параметр -x/--proxy <host[:port]> к curl, запустите этот скрипт и снова сравните файлы.Если некоторые ответы совпадают с другими, вы можете быть уверены, что это проблема прокси-сервера.

3 голосов
/ 10 марта 2012

Вообще говоря, для проверки того, выполняются ли HTTP-запросы по сети, вы можете использовать инструмент «сниффинг», который анализирует сетевой трафик, например:

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

Хотя это и не ответ, его стоит задуматься: возможно ли, что сервер (или некоторыепромежуточный прокси) возвращает вам кешированный контент?Если вы выполняете много запросов (одновременно или почти одновременно) для одного и того же контента, сервер может возвращать вам кэшированный контент, поскольку он решил, что информация еще не «просрочена».Фактически протокол HTTP обеспечивает директивы кэширования для такой функциональности.Вот сайт, который предоставляет общий обзор различных механизмов кэширования HTTP:

http://betterexplained.com/articles/how-to-optimize-your-site-with-http-caching/

Надеюсь, это даст вам отправную точку.Если вы уже рассматривали эти возможности, тогда это здорово.

1 голос
/ 10 марта 2012

Вы можете попытаться добавить какой-либо уникальный фиктивный параметр к URL-адресу при каждом запросе, чтобы попытаться победить любое кэширование на основе URL-адреса (на сервере или где-то в пути).Это не будет работать, если кеширование не является проблемой, или если сервер достаточно умен, чтобы отклонять запросы с неизвестными параметрами, или если сервер кеширует, но только на основе параметров, о которых он заботится, или если выбранное вами имя параметра сталкивается спараметр, который на самом деле использует сайт.

Если вы используете этот URL-адрес http://www.example.org/index.html, попробуйте использовать http://www.example.org/index.html?dummy=1

Установите для фиктивного значения другое значение для каждого запроса.

...