HTTP caching: why is browser not checking server at all before presuming cached file is current?

早过忘川 提交于 2020-01-07 08:07:23

问题


This is about some code I inherited; the intent is clear, but (at least in Firefox and Chrome) it is not behaving as intended.

The idea is clearly to build a PNG based on client-side data and to cache it unless and until that data changes. The intent presumably is that the state of the PNG is preserved regardless of whether or not the client is using cookies, local storage, etc., but at the same time the server does not preserve data about this client.

Client-side JavaScript:

function read_or_write_png(name, value) {
    // WRITE if value is defined, non-null, etc., get otherwise
    if (value) {
        // WRITE

        // Use cookie to convey new data to server
        document.cookie = 'bx_png=' + value + '; path=/';        

        // bx_png.php generates the image
        // based off of the http cookie and returns it cached
        var img = new Image();
        img.style.visibility = 'hidden';
        img.style.position = 'absolute';
        img.src = 'bx_png.php?name=' + name; // the magic saying "load this".
                                             // 'name' is not consulted server-side,
                                             //  it's here just to get uniqueness
                                             //  for what is cached.
    } else {
        // READ

        // Kill cookie so server should send a 304 header
        document.cookie = 'bx_png=; expires=Mon, 20 Sep 2010 00:00:00 UTC; path=/';

        // load the cached .png
        var img = new Image();
        img.style.visibility = 'hidden';
        img.style.position = 'absolute';
        img.src = 'bx_png.php?name=' + name;            
    }
}

Server-side PHP in bx_png.php:

if (!array_key_exists('bx_png', $_COOKIE) || !isset($_COOKIE['bx_png'])) {
    // we don't have a cookie. Client side code does this on purpose. Force cache.
    header("HTTP/1.1 304 Not Modified");
} else {
    header('Content-Type: image/png');
    header('Last-Modified: Wed, 30 Jun 2010 21:36:48 GMT');
    header('Expires: Tue, 31 Dec 2030 23:30:45 GMT');
    header('Cache-Control: private, max-age=630720000');
    // followed by the content of the PNG        
}

This works fine to write the PNG the first time and cache it, but clearly the intention is to be able to call this again, pass a different value for the same name, and have that cached. In practice, once the PNG has been cached, it would appear (via Fiddler) that the server is not called at all. That is, on an attempted read, rather than go to the server and get a 304 back, the browser just takes the content from the cache without ever talking to the server. In and of itself, that part is harmless, but of course what is harmful is that the same thing happens on an attempted write, and the server never has a chance to send back a distinct PNG based on the new value.

Does anyone have any idea how to tweak this to fulfill its apparent intention? Maybe something a bit different in the headers? Maybe some way of clearing the cache from client-side? Maybe something else entirely that I haven't thought of? I'm a very solid developer in terms of both server-side and client-side, but less experienced with trickiness like this around the HTTP protocol as such.


回答1:


You need to add must-revalidate to your Cache-Control header to tell the browser to do that.




回答2:


Try cache-control: no-store as it fixed this exact same problem for me in Safari/WebKit. (I think Chrome fixed it in the time since your question.)

It's still an open WebKit bug but they added a fix for this header.



来源:https://stackoverflow.com/questions/19500094/http-caching-why-is-browser-not-checking-server-at-all-before-presuming-cached

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!