我正在尝试使用 Java 的 HttpURLConnection 进行“条件获取”,但我从未收到 304 状态代码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7095897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 18:36:20  来源:igfitidea点击:

I'm trying to use Java's HttpURLConnection to do a "conditional get", but I never get a 304 status code

javahttpcachinghttp-caching

提问by sanity

Here is my code:

这是我的代码:

    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
    }

I never seem to get the HTTP_NOT_MODIFIED response code, even hitting the same server several times in quick succession - where there is definitely no change to the page. Also, conn.getHeaderField("ETag") always seems to respond null, and sometimes conn.getHeaderFieldDate("Last-Modified", 0) returns 0. I've tried this against a variety of web servers.

我似乎从来没有得到 HTTP_NOT_MODIFIED 响应代码,即使快速连续多次访问同一台服务器 - 页面绝对没有变化。此外, conn.getHeaderField("ETag") 似乎总是响应 null,有时 conn.getHeaderFieldDate("Last-Modified", 0) 返回 0。我已经针对各种 Web 服务器尝试过这个。

Can anyone tell me what I'm doing wrong?

谁能告诉我我做错了什么?

回答by BalusC

You're all dependent on the server config.

你都依赖于服务器配置。

If you get an Expiresresponse header, then it just means that you don't need to request anything until the specified expire time. If you get a Last-Modifiedresponse header, then it means that you should be able to use If-Modified-Sinceto test it. If you get an ETagresponse header, then it means that you should be able to use If-None-Matchto test it.

如果你得到一个Expires响应头,那么它只是意味着你不需要在指定的过期时间之前请求任何东西。如果你得到一个Last-Modified响应头,那么这意味着你应该可以If-Modified-Since用来测试它。如果你得到一个ETag响应头,那么这意味着你应该可以If-None-Match用来测试它。

Lets take http://cdn3.sstatic.net/stackoverflow/img/favicon.icoas an example (the Stackoverflow's favicon image):

让我们以http://cdn3.sstatic.net/stackoverflow/img/favicon.ico为例(Stackoverflow 的 favicon 图片):

URLConnection connection = new URL("http://cdn3.sstatic.net/stackoverflow/img/favicon.ico").openConnection();
System.out.println(connection.getHeaderFields());

This gives:

这给出:

{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]}

{null=[HTTP/1.1 200 OK],ETag=["9d9bd8b1165cb1:0"],日期=[2011 年 8 月 17 日星期三 17:57:07 GMT],内容长度=[1150],上次修改=[ 2010 年 10 月 6 日星期三 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]}

Now, do a If-Modified-Sincewith the same value as Last-Modified:

现在,使用If-Modified-Since与以下相同的值Last-Modified

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());

This gives as expected a 304:

正如预期的那样,这给出了 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]}

{null=[HTTP/1.1 304 Not Modified], ETag=["9d9bd8b1165cb1:0"], Date=[Wed, 17 August 2011 17:57:42 GMT], Last-Modified=[Wed, 06 Oct 2010 02:格林威治标准时间 53:46],连接=[保持活动],服务器=[nginx/0.8.36],X-Cache=[HIT],Cache-Control=[max-age=604800]}

Now, do a If-None-Matchwith the same value as ETag:

现在,使用If-None-Match与以下相同的值ETag

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());

This gives unexpectedlya 200:

出乎意料地给出了 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]}

{null=[HTTP/1.1 200 OK],ETag=["9d9bd8b1165cb1:0"],日期=[2011 年 8 月 17 日星期三 18:01:42 GMT],内容长度=[1150],上次修改=[ 2010 年 10 月 6 日星期三 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]}

Even more surprising, when the both headers are set with random garbage value as ETag, the server still gives a 304. This is an indication that the If-None-Matchis completely ignored by the server behind http://cdn3.sstatic.net. That might be a (proxy) configuration issue or be done fully awarely (not for obvious reasons imho).

更令人惊讶的是,当两个标头都设置为随机垃圾值时ETag,服务器仍然给出 304。这表明http://cdn3.sstatic.netIf-None-Match后面的服务器完全忽略了。这可能是(代理)配置问题,或者完全有意识地完成(不是出于显而易见的原因恕我直言)。

回答by fider

Or shorter :)

或更短:)

Just try set connection timeout other than 0.

只需尝试设置 0 以外的连接超时

conn.setConnectionTimeout( 3000);

Do it after .openConnection()

在 .openConnection() 之后做

final HttpURLConnection conn = (HttpURLConnection) sourceURL.openConnection();
conn.setConnectionTimeout( 3000);

If not set also readTimeout other than 0.

如果未设置,则 readTimeout 也不是 0。

conn.setReadTimeout( 3000);