4

I am trying to get Opera to re-request a page every time instead of just serving it from the cache. I'm sending the 'Cache-control: no-cache' and 'Pragma: no-cache' response headers but it seems as if Opera is just ignoring these headers. It works fine in other browsers - Chrome, IE, Firefox.

How do I stop Opera from caching pages? What I want to be able to do is have Opera re-request a page when the user clicks the Back button on the browser.

Nishkar
  • 63
  • 1
  • 1
  • 6

4 Answers4

5

As a user, I absolutely detest pages that slow down my history navigation by forcing re-loads when I use the back button. (If the browser you use on a daily basis paid attention to the various caching directives and let them affect history navigation the way you want as a developer you'd probably notice some sites slowing down yourself...)

If you have a very strong use case for doing this I'd say your architecture might be "wrong" in some sense - for example, if you're switching between different "views" of constantly updating data and thus want to enforce re-load when users go back perhaps using Ajaxy techniques for loading the constantly changing data into the current page would be better?

Opera's implementation is on purpose - "caching" is seen as conceptually different from "history navigation", the former is more about storing things on disk and between sessions, the latter is switching back to a temporarily hidden page you just visited, in the state you left it.

However, if you really, really need it there is a loophole in this policy that enables the behaviour you want. Sending "Cache-control: must-revalidate" will force Opera to re-load every page on navigation, but only if you're sending the page over https. (This is a feature requested by and intended for paranoid banks, it slows down way too many normal sites if applied on http).

hallvors
  • 5,603
  • 1
  • 20
  • 37
  • 3
    "This is a feature requested by and intended for paranoid banks, it slows down way too many normal sites if applied on http" Are you saying browsers shouldn't really be used for applications that may have sensitive data? :-) – bunn_online May 20 '10 at 14:33
  • 2
    If data is truly sensitive, sites should use https. :-) There is a hole in the web specifications here, as there is no concept of "sessions" shared between server and browser. If the server could tell the browser "the user just logged out/timed out and we closed her session, please disallow using back button to see history since the session was started" we'd be able to find a better balance between usability and security. – hallvors May 21 '10 at 07:34
  • 2
    I agree with both points: (i) there is a hole in the web specification with regards a "shared session state" & (ii) https should be used for truly sensitive. But, "truly sensitive data" is an indication that data security is not digital but an analogue measure. Other browsers support this by allowing no cache & must-revalidate to work regardless, which allows further scope in managing security/privacy. Opera doesn't support this - right or wrong, I am not concerned. I need a solution to get around this inconsistency. U work at Opera, what can u suggest? (i.e. script, header, etc.) Thks – Forer May 21 '10 at 10:35
  • 1
    There is no way I know about to reliably force revalidation if you are not on https. We're working on proposals to fix this problem, for example: http://www.ietf.org/id/draft-pettersen-cache-context-05.txt An actual implementation is probably some time away - pending further discussion of the proposal. – hallvors Sep 03 '10 at 10:13
2

It sounds like your problem is related to this answer. After testing your header and the suggested headers, I could only reproduce your expected behavior in Internet Explorer.

Community
  • 1
  • 1
Quai
  • 183
  • 3
  • 1
    I repeatedly reproduce this issue on Opera. It seems to be the only inconsistent browser. I have read about their strict, principled approach to handling caching. But this is practically just looking like a security hole without doing extra leg work. I'd really like an explicit solution that can be implemented to nishkarr's questions as well. The header cache control reponse headers do not work in opera as in other browsers. What is the work around? – Forer May 20 '10 at 14:30
2

SIMPLE SERVERSIDE CACHE CONTROL WITHOUT HEADERS OR FRONTEND SCRIPTS

Zero Dependency, Universal Language Edition


You can force re-caching globally without using a header by appending an md5 or sha1 checksum to your filename.

That way it will cache if it is an exact match, and otherwise treat it like a new resource.

  • Works in all browsers
  • Validates as strict HTML5 (originally did not, but this has been updated. Untested for XHTML, but probably not valid for that)
  • Does not require extra headers
  • Keeps frontend concerns and backend concerns nicely decoupled.
  • Does not require client side sanity checks or source validation.
  • Anything that can print html can do this consistently, including static content
  • If not static, easy to extend runtime control to end users (with authentication, if desired) that allows for simple page flags to determine minified, prettified, or debug source being returned.
  • Entirely encapsulates client cache control in the content serving mechanism, which makes things super simple to maintain.
  • As a side perk, introduces versioned client-side caching automatically by deferring to the checksums the browser has cached, which can be useful if you have alternate versions and need to unit test a release package to determine it's minimum stable dependency versions or something.

  • You don't ever have to fiddle with your browser to get the caching not to interfere with your development process again.

  • This approach also can be used for versioned images, video, audio, pdfs, etc. Pretty much any resource that is served as static data will operate similarly, cache on the first request for the content, and persist automatically without further consideration if the file does not change.


This is RFC valid markup. Notice the script and link tags have a get string:

?checksum=ba411cafee2f0f702572369da0b765e2

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">

  <title>Client Cache Control Example</title>
  <meta name="description" content="You're only going to cache this when the content changes, and always when the content changes.">
  <meta name="author" content="https://stackoverflow.com/users/1288121/mopsyd">

  <!-- Example Stylesheet -->
  <link rel="stylesheet" href="css/styles.css?checksum=ba411cafee2f0f702572369da0b765e2">

  <!-- Example Script -->
  <script src="js/scripts.js?checksum=ba411cafee2f0f702572369da0b765e2"></script>
</head>
<body>
</body>
</html>

The GET string ?checksum=ba411cafee2f0f702572369da0b765e2 refers to either an MD5 or SHA1 hash of the filesize of the resource. It can be obtained through a command line, language construct, or by hashing it from the value of the Content-Length: header. You then construct your href or src attribute by appending it as a GET string to the filename.

This browser will interpret these as distinct, and cache separately.

The server will ignore the GET parameter if it is a static resource, but if it is served dynamically, then the GET parameter will be available to the interpreting language.

This means that whenever that hash changes in the links, the browser will cache that specific version independently one time, and then keep it until forever, or Expires: goes by, whichever is sooner.

Since the checksum is a direct reflection of the filesize, you can set Expires: to forever and it doesn't make much difference. You will still see your changes immediately as soon as that file changes even a single byte.

  • Generate your css or js source with whatever utilities you normally do.

  • Run an md5 or sha1 checksum on the filesize at runtime if you are serving dynamically, and at compiletime if you are generating static content (like ApiGen docs, for example).

  • Serve the normal file with the hash as a GET string appended to the filename (eg: styles.css becomes styles.css?checksum=ba411cafee2f0f702572369da0b765e2)

  • Any change in the file forces a recache, which means you see the real value reflected immediately.

  • Optional, but rad: An additional benefit of this approach is that you can easily set up a dev GET flag, which will make ALL frontend source resolve to prettified dev source with any of your own custom debug functionality enabled, or use it to interpret versioning flags. You can do a redundant check to make sure that flag is only passed from a known development IP address, proxy authentication, etc. by the server and otherwise is not honored if you need it secure. I usually divide my frontend source up whenever possible similar to this:

    • This is what it is doing on live right now (minified production, cached, default, ?checksum=ba411cafee2f0f702572369da0b765e2).
    • This is what it ought to be doing on live right now, prettified enough for me to read (prettified production, never cached, ?debug_pretty_source=true).
    • This is what I use to figure out what isn't doing what it ought to on live if it exists in both of the previous (prettified with debug enabled, never cached, ACL/whitelist authorized, ?debug_dev_enable=true or similar).

You can apply the same principle to package releases by using version numbers instead of checksums, provided your versions don't change. Checksums are less readable but easier to automate and keep in sync with exact changes, but version suffixes are useful for testing package stability also, provided the version number reflects an immutable resource.

mopsyd
  • 1,720
  • 3
  • 19
  • 28
  • It should be noted that http transit proxies sometimes interfere with this using `GET`, which depend on the specific network path of the request to your server. In that case, this can be circumvented by appending the hash directly to the filename instead of using a get string, and then using an `.htaccess` rewrite rule to strip them, which works even in the case of proxy interference. It's not usually an issue, but sometimes can be in certain edge cases. Eg: `styles.ba411cafee2f0f702572369da0b765e2.css` instead of `styles.css?checksum=ba411cafee2f0f702572369da0b765e2` – mopsyd Nov 11 '17 at 20:42
0

Found this whilst searching for solution. No joy, so wrote some javascript to solve the problem which may be of use to others.

In <HEAD> above any other javascript:

<script>
    if( typeof(opera) != 'undefined' ) { // only do for Opera
       if (window.name == 'previously_loaded') { // will be "" before page is loaded
            alert('Reloading Page from Server'); // for testing
            window.name = ''; // prevent multiple reload
            window.location.reload(true);
       }
    }
</script>

Now change window name so Opera detects it on subsequent load from cache:

window.name = 'previously_loaded';

Insert this line in one of your js blocks that wont be executed during “window load” causing infinite reload. For me there was no need to refresh the page unless someone has exited by a link, so I just added it to my onclick/onunload function.

Before and after demos here with a few more notes. I intend to add it to my blog. I've only a few late versions of Opera, so I would appreciate some tries of the demo before I get egg on my face.

Edit: Just realised that if a later visited site changes window name (its persistent) then back-tab reload wont happen. Just alter above if statement to:

 if (window.name != "") {

Demo worked fine when open in multiple tabs; but I vaguely recollect that window names should be unique; so I've altered the demo to generate a unique name.

window.name = new Date().getTime();
scytale
  • 1,206
  • 1
  • 11
  • 12