【问题标题】:Java HttpClient seems to be caching contentJava HttpClient 似乎正在缓存内容
【发布时间】:2012-03-09 22:09:29
【问题描述】:

我正在构建一个简单的网络爬虫,我需要获取同一页面几百次,并且页面中有一个动态属性,应该在每次请求时更改。我已经构建了一个基于多线程 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");
}

【问题讨论】:

  • 可以缓存在服务器端。
  • 您可能正在编写线程不安全的代码,并且每当您下载数据时,旧结果都会被新结果覆盖。没有代码很难分辨。
  • 我已经用代码更新了问题

标签: java multithreading http httpclient apache-httpcomponents


【解决方案1】:

HTTPClient 默认不使用缓存(仅当您使用DefaultHttpClient 类时)。如果您使用CachingHttpClient 即启用缓存的HttpClient 接口装饰器,它会这样做:

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

然后,它分析If-Modified-SinceIf-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。他们都应该有你提到的差异。然后,在 curl 中添加-x/--proxy &lt;host[:port]&gt; 选项,执行此脚本并再次比较文件。如果某些响应与其他响应相同,则可以确定这是代理服务器问题。

【讨论】:

【解决方案2】:

一般来说,为了测试是否通过网络发出 HTTP 请求,您可以使用分析网络流量的“嗅探”工具,例如:

我非常怀疑 HttpClient 正在执行任何类型的缓存(这意味着它需要将页面存储在内存或磁盘上 - 而不是它的功能之一)。

虽然这不是一个答案,但值得深思:服务器(或介于两者之间的某个代理)是否可能正在返回您缓存的内容?如果您对同一内容执行许多请求(同时或几乎同时),则服务器可能会返回您缓存的内容,因为它已确定信息尚未“过期”。事实上,HTTP 协议为此类功能提供了缓存指令。这是一个提供不同 HTTP 缓存机制的高级概述的网站:

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

我希望这能给你一个起点。如果您已经考虑过这些途径,那就太好了。

【讨论】:

    【解决方案3】:

    您可以尝试在每个请求的 URL 中附加一些唯一的虚拟参数,以尝试阻止任何基于 URL 的缓存(在服务器中或沿途某处)。如果缓存不是问题,或者如果服务器足够聪明以拒绝带有未知参数的请求,或者如果服务器正在缓存但仅基于它关心的参数,或者如果您选择的参数名称与网站实际使用的参数。

    如果这是您使用的 URL http://www.example.org/index.html 尝试使用 http://www.example.org/index.html?dummy=1

    为每个请求将 dummy 设置为不同的值。

    【讨论】:

    • 我也在使用 FixedThreadPool 来执行线程:ExecutorService pool = Executors.newFixedThreadPool(10); for(int i=0;i&lt;count;i++) pool.submit(new GetThread(i)); pool.submit;
    猜你喜欢
    • 2016-11-26
    • 1970-01-01
    • 1970-01-01
    • 2013-05-27
    • 1970-01-01
    • 1970-01-01
    • 2013-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多