Я пытаюсь использовать Java HttpURLConnection для "условного получения", но я никогда не получаю код состояния 304

Вот мой код:

    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") всегда кажется пустым, а иногда conn.getHeaderFieldDate("Last-Modified", 0) возвращает 0. Я пробовал это на различных веб-серверах.

Может кто-нибудь сказать мне, что я делаю не так?

2 ответа

Решение

Вы все зависит от конфигурации сервера.

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

Давайте возьмем http://cdn3.sstatic.net/stackru/img/favicon.ico в качестве примера (изображение значка Stackru):

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

Это дает:

{null = [HTTP / 1.1 200 OK], ETag=["9d9bd8b1165cb1:0"], дата = [ср, 17 авг. 2011 17:57:07 GMT], длина контента =[1150], последняя модификация = [ Ср, 06 октября 2010 02:53:46 GMT], Content-Type=[image/x-icon], Connection=[keep-alive], Accept-Ranges=[байты], Server=[nginx/0.8.36], X-Cache=[HIT], Cache-Control=[max-age=604800]}

Теперь сделайте If-Modified-Since с тем же значением, что и Last-Modified:

URLConnection connection = new URL("http://cdn3.sstatic.net/stackru/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 не изменен], ETag=["9d9bd8b1165cb1:0"], дата = [ср, 17 авг 2011 17:57:42 GMT], последняя модификация = [ср, 06 окт 2010 02: 53:46 GMT], соединение = [keep-alive], сервер = [nginx / 0.8.36], X-Cache = [HIT], Cache-Control = [max-age = 604800]}

Теперь сделайте If-None-Match с тем же значением, что и ETag:

URLConnection connection = new URL("http://cdn3.sstatic.net/stackru/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"], дата = [ср, 17 августа 2011 18:01:42 GMT], длина контента =[1150], последняя модификация = [ Ср, 06 октября 2010 02:53:46 GMT], Content-Type=[image/x-icon], Connection=[keep-alive], Accept-Ranges=[байты], Server=[nginx/0.8.36], X-Cache=[HIT], Cache-Control=[max-age=604800]}

Еще более удивительно, когда оба заголовка установлены со случайным значением мусора как ETag сервер по-прежнему выдает 304. Это указывает на то, что If-None-Match полностью игнорируется сервером за http://cdn3.sstatic.net/. Это может быть проблемой конфигурации (прокси) или сделано полностью осознанно (не по очевидным причинам imho).

Или короче:)

Просто попробуйте установить время ожидания соединения, отличное от 0.

conn.setConnectionTimeout( 3000);

Сделайте это после.openConnection()

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

Если не установлено, также readTimeout, отличный от 0.

conn.setReadTimeout( 3000);
Другие вопросы по тегам