我尝试使用Java的HttpURLConnection进行“条件获取”,但我从来没有收到304状态码

5

以下是我的代码:

    final HttpURLConnection conn = (HttpURLConnection) sourceURL.openConnection();
    if (cachedPage != null) {
        if (cachedPage.eTag != null) {
            conn.setRequestProperty("If-None-Match", cachedPage.eTag);
        }
        conn.setIfModifiedSince(cachedPage.pageLastModified);
    }

    conn.connect();

    if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {

        newCachedPage.eTag = conn.getHeaderField("ETag");
        newCachedPage.pageLastModified = conn.getHeaderFieldDate("Last-Modified", 0);

    } else if (conn.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) {
        // Never reaches here
    }

我似乎从未收到HTTP_NOT_MODIFIED响应代码,即使我在快速连续访问同一服务器时 - 页面明确没有任何更改。此外,conn.getHeaderField(“ETag”)似乎总是返回null,有时conn.getHeaderFieldDate(“Last-Modified”,0)返回0。 我已尝试在多个Web服务器上测试。

有人能告诉我我做错了什么吗?


只有在服务器支持的情况下才能成功执行。也许它正在使用Expires来进行缓存和/或期望一个If-Not-Modified请求头?或者是因为流式代码由自定义servlet中的新手编写,所以服务器支持有漏洞/较差?调查默认HTTP GET请求的所有响应头,以了解服务器似乎支持哪些缓存机制。有关HTTP缓存机制的深入背景信息,请阅读此教程:http://www.mnot.net/cache_docs/ - BalusC
我正在测试的服务器是基于相当标准的 LAMP 堆栈的 Wordpress。服务器支持条件获取真的很少见吗? - sanity
嗯,你为什么打上了servlets标签?不管怎样,你获取到的请求头信息如何? - BalusC
尝试访问http://cdn3.sstatic.net/stackoverflow/img/favicon.ico(从此stackoverflow页面请求中获取的URL)。它会返回一个Last-Modified头,值为Wed, 06 Oct 2010 02:53:46 GMT。如果您发送一个新的请求,并带上If-Modified-Since头,值恰好为该值,您应该会得到一个304响应。至少在这里是这样的。 - BalusC
我把评论总结成了一个答案。 - BalusC
显示剩余3条评论
2个回答

17
你们都依赖于服务器配置。如果你收到一个“Expires”响应头,那就意味着你不需要在指定的过期时间之前请求任何内容。如果你收到一个“Last-Modified”响应头,那就意味着你应该能够使用“If-Modified-Since”进行测试。如果你收到一个“ETag”响应头,那就意味着你应该能够使用“If-None-Match”进行测试。
让我们以http://cdn3.sstatic.net/stackoverflow/img/favicon.ico为例(Stackoverflow的网站图标)。
URLConnection connection = new URL("http://cdn3.sstatic.net/stackoverflow/img/favicon.ico").openConnection();
System.out.println(connection.getHeaderFields());

这将会得到:

{null=[HTTP/1.1 200 OK], ETag=["9d9bd8b1165cb1:0"], Date=[Wed, 17 Aug 2011 17:57:07 GMT], Content-Length=[1150], Last-Modified=[Wed, 06 Oct 2010 02:53:46 GMT], Content-Type=[image/x-icon], Connection=[keep-alive], Accept-Ranges=[bytes], Server=[nginx/0.8.36], X-Cache=[HIT], Cache-Control=[max-age=604800]}

现在,使用与 Last-Modified 相同的值进行 If-Modified-Since 操作:

URLConnection connection = new URL("http://cdn3.sstatic.net/stackoverflow/img/favicon.ico").openConnection();
connection.setRequestProperty("If-Modified-Since", "Wed, 06 Oct 2010 02:53:46 GMT");
System.out.println(connection.getHeaderFields());

这将返回一个预期的304:

{null=[HTTP/1.1 304 Not Modified], ETag=["9d9bd8b1165cb1:0"], Date=[Wed, 17 Aug 2011 17:57:42 GMT], Last-Modified=[Wed, 06 Oct 2010 02:53:46 GMT], Connection=[keep-alive], Server=[nginx/0.8.36], X-Cache=[HIT], Cache-Control=[max-age=604800]}

现在,使用与ETag相同的值执行If-None-Match

URLConnection connection = new URL("http://cdn3.sstatic.net/stackoverflow/img/favicon.ico").openConnection();
connection.setRequestProperty("If-None-Match", "9d9bd8b1165cb1:0");
System.out.println(connection.getHeaderFields());

这意外地给出了一个200:

{null=[HTTP/1.1 200 OK], ETag=["9d9bd8b1165cb1:0"], Date=[Wed, 17 Aug 2011 18:01:42 GMT], Content-Length=[1150], Last-Modified=[Wed, 06 Oct 2010 02:53:46 GMT], Content-Type=[image/x-icon], Connection=[keep-alive], Accept-Ranges=[bytes], Server=[nginx/0.8.36], X-Cache=[HIT], Cache-Control=[max-age=604800]}

更令人惊讶的是,当两个标头的值都设置为随机垃圾值时,服务器仍然会给出304。这表示服务器在http://cdn3.sstatic.net后面完全忽略了If-None-Match 。这可能是一个(代理)配置问题,也可能是完全有意为之(我个人认为不是很明显的原因)。


可以帮我一下吗?我尝试使用你的方法,但从未返回304。http://stackoverflow.com/questions/13605425/http-conditional-get。 - Moe

-4

或者更短一点 :)

尝试设置连接超时时间不为0

conn.setConnectionTimeout( 3000);

在.openConnection()之后执行。
final HttpURLConnection conn = (HttpURLConnection) sourceURL.openConnection();
conn.setConnectionTimeout( 3000);

如果没有设置readTimeout,也要读取其他值。

conn.setReadTimeout( 3000);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接