Prevent safari loading from cache when back button is clicked

JavascriptCachingSafariBack Button

Javascript Problem Overview


Got an issue with safari loading old youtube videos when back button is clicked. I have tried adding onunload="" (mentioned here https://stackoverflow.com/questions/5297122/preventing-cache-on-back-button-in-safari-5) to the body tag but it doesn't work in this case.

Is there any way to prevent safari loading from cache on a certain page?

Javascript Solutions


Solution 1 - Javascript

Your problem is caused by back-forward cache. It is supposed to save complete state of page when user navigates away. When user navigates back with back button page can be loaded from cache very quickly. This is different from normal cache which only caches HTML code.

When page is loaded for bfcache onload event wont be triggered. Instead you can check the persisted property of the onpageshow event. It is set to false on initial page load. When page is loaded from bfcache it is set to true.

Kludgish solution is to force a reload when page is loaded from bfcache.

window.onpageshow = function(event) {
    if (event.persisted) {
        window.location.reload() 
    }
};

If you are using jQuery then do:

$(window).bind("pageshow", function(event) {
    if (event.originalEvent.persisted) {
        window.location.reload() 
    }
});

Solution 2 - Javascript

All of those answer are a bit of the hack. In modern browsers (safari) only on onpageshow solution work,

window.onpageshow = function (event) {
    if (event.persisted) {
        window.location.reload();
    }
};

but on slow devices sometimes you will see for a split second previous cached view before it will be reloaded. Proper way to deal with this problem is to set properly Cache-Control on the server response to one bellow

'Cache-Control', 'no-cache, max-age=0, must-revalidate, no-store'

Solution 3 - Javascript

Yes the Safari browser does not handle back/foreward button cache the same like Firefox and Chrome does. Specially iframes like vimeo or youtube videos are cached hardly although there is a new iframe.src.

I found three ways to handle this. Choose the best for your case. Solutions tested on Firefox 53 and Safari 10.1

1. Detect if user is using the back/foreward button, then reload whole page or reload only the cached iframes by replacing the src

if (!!window.performance && window.performance.navigation.type === 2) {
			// value 2 means "The page was accessed by navigating into the history"
			console.log('Reloading');
			//window.location.reload(); // reload whole page
			$('iframe').attr('src', function (i, val) { return val; }); // reload only iframes
		}

2. reload whole page if page is cached

window.onpageshow = function (event) {
		if (event.persisted) {
			window.location.reload();
		}
	};

3. remove the page from history so users can't visit the page again by back/forward buttons

$(function () {
			//replace() does not keep the originating page in the session history,
			document.location.replace("/Exercises#nocache"); // clear the last entry in the history and redirect to new url
		});

Solution 4 - Javascript

You can use an anchor, and watch the value of the document's location href;

Start off with http://acme.co/, append something to the location, like '#b';

So, now your URL is http://acme.co/#b, when a person hits the back button, it goes back to http://acme.co, and the interval check function sees the lack of the hash tag we set, clears the interval, and loads the referring URL with a time-stamp appended to it.

There are some side-effects, but I'll leave you to figure those out ;)

<script>
document.location.hash = "#b";
var referrer = document.referrer;

// setup an interval to watch for the removal of the hash tag
var hashcheck = setInterval(function(){
    if(document.location.hash!="#b") {

    // clear the interval
    clearInterval(hashCheck);

    var ticks = new Date().getTime();
    // load the referring page with a timestamp at the end to avoid caching
    document.location.href.replace(referrer+'?'+ticks);
    }
},100);
</script>

This is untested but it should work with minimal tweaking.

Solution 5 - Javascript

The behavior is related to Safari's Back/Forward cache. You can learn about it on the relevant Apple documentation: http://web.archive.org/web/20070612072521/http://developer.apple.com/internet/safari/faq.html#anchor5

Apple's own fix suggestion is to add an empty iframe on your page:

<iframe style="height:0px;width:0px;visibility:hidden" src="about:blank">
	this frame prevents back forward cache
</iframe>

(The previous accepted answer seems valid too, just wanted to chip in documentation and another potential fix)

Solution 6 - Javascript

I had the same issue with using 3 different anchor links to the next page. When coming back from the next page and choosing a different anchor the link did not change.

so I had

<a href="https://www.example.com/page-name/#house=house1">House 1</a>
<a href="https://www.example.com/page-name/#house=house2">View House 2</a>
<a href="https://www.example.com/page-name/#house=house3">View House 3</a>

Changed to

<a href="/page-name#house=house1">House 1</a>
<a href="/page-name#house=house2">View House 2</a>
<a href="/page-name#house=house3">View House 3</a>

Also used for safety:

// Javascript
window.onpageshow = function(event) {
    if (event.persisted) {
        window.location.reload() 
    }
};

// JQuery
$(window).bind("pageshow", function(event) {
    if (event.originalEvent.persisted) {
        window.location.reload() 
    }
});

None of the solutions found online to unload, reload and reload(true) singularily didn't work. Hope this helps someone with the same situation.

Solution 7 - Javascript

First of all insert field in your code:

<input id="reloadValue" type="hidden" name="reloadValue" value="" />

then run jQuery:

jQuery(document).ready(function()
{
        var d = new Date();
        d = d.getTime();
        if (jQuery('#reloadValue').val().length == 0)
        {
                jQuery('#reloadValue').val(d);
                jQuery('body').show();
        }
        else
        {
                jQuery('#reloadValue').val('');
                location.reload();
        }
});

Solution 8 - Javascript

There are many ways to disable the bfcache. The easiest one is to set an 'unload' handler. I think it was a huge mistake to make 'unload' and 'beforeunload' handlers disable the bfcache, but that's what they did (if you want to have one of those handlers and still make the bfcache work, you can remove the beforeunload handler inside the beforeunload handler).

window.addEventListener('unload', function() {})

Read more here:

https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/1.5/Using_Firefox_1.5_caching

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMark StegglesView Question on Stackoverflow
Solution 1 - JavascriptMika TuupolaView Answer on Stackoverflow
Solution 2 - Javascriptwaj-er-rrView Answer on Stackoverflow
Solution 3 - JavascriptJavan R.View Answer on Stackoverflow
Solution 4 - JavascriptLarry WilliamsonView Answer on Stackoverflow
Solution 5 - JavascriptSimon BoudriasView Answer on Stackoverflow
Solution 6 - Javascriptuser3615851View Answer on Stackoverflow
Solution 7 - JavascriptIvan Laharnar mink.siView Answer on Stackoverflow
Solution 8 - JavascriptB TView Answer on Stackoverflow