Explain Codes LogoExplain Codes Logo

Is Safari on iOS 6 caching $.ajax results?

javascript
ajax
caching
safari
Alex KataevbyAlex Kataev·Jan 14, 2025
TLDR
$.ajaxSetup({ cache: false }); // Voila! Global eradication of caching

Setting cache: false globally nukes iOS 6 Safari's habit of caching $.ajax without tweaking individual calls. Result? Shiny new server data every time.

Why does Safari on iOS 6 hold on to old treasures?

The webkit engine for Safari on iOS 6 has a penchant for clinging onto POST requests. The HTTP specification says it's A-OK unless the Cache-Control header stomps its foot and says otherwise. For those who don't want caching surprises, heavy-duty solutions include:

  1. Branding AJAX responses with Cache-Control: no-cache.
  2. Append a timestamp that changes every time.
  3. Twist Apache's arm to include Cache-Control headers for POST requests.

But how do we tame servers, exactly?

Let Apache do the dirty work

Apache can be your henchman. Include the following in your config:

<FilesMatch "\.(php|cgi|pl)$"> Header set Cache-Control "no-cache" // Stamp every POST request with a big "Do not cache!" sticker </FilesMatch>

Double down with cache-proof headers

Because more is more, it doesn't hurt to add:

Pragma: no-cache // Because "I said no caching!" wasn't clear the first time

Just like HDR on your iPhone, this provides an additional layer of caching prevention.

When static web services say no

Like a strict teacher, static web services should always set cacheability to NoCache. No cached responses allowed - not on my watch!

I'm a client-side script. What can I do?

Timestamp trick

Slap on a timestamp using JavaScript’s getTime(), and you're done:

function noCacheUrl(url) { return url + ((url.indexOf('?') > -1 ? '&' : '?') + 'timestamp=' + new Date().getTime()); // It's time to change, every time }

Modifying AJAX requests - swiftly, softly

jQuery.ajaxPrefilter lets you append timestamps without the headache:

$.ajaxPrefilter(function(options, originalOptions, jqXHR) { if (originalOptions.type.toUpperCase() === "POST") { options.url = noCacheUrl(originalOptions.url); // Dress up every POST request with a snazzy new timestamp } });

$.ajaxSetup for global headers - like a boss

Let AJAX know who's the boss - set cache-control headers globally for all requests:

$.ajaxSetup({ beforeSend: function(jqXHR) { jqXHR.setRequestHeader("Cache-Control", "no-cache"); // Cache? Where we're going, we don't need cache. jqXHR.setRequestHeader("Pragma", "no-cache"); // In case the memo didn't get past the front desk } });

A quick detour: Picture time!

See Safari on iOS 6 as a librarian (👩‍🏫) hoarding books (📚 = requests). When "books" are returned, they go into the special "Here's what you read last week" shelf. Called "Cache," this shelf avoids you hunting high and low for the same books. To get a freshly printed edition, we ensure each "book request" comes with a unique secret message (🔖 = unique timestamp).

Coffee-break strategies to mull over

Knock, knock. Who’s there? Unwanted caching.

Make sure all developers are clued in about iOS 6 Safari's caching party trick. Because, mind-reading is the last thing you want in your job description.

Not in the jQuery jamboree? No problem!

If you're not on the jQuery boat, XMLHttpRequest or another library will help you steer clear of caching icebergs.

Flex your caching strategy muscle

From altering requests to switching up response headers – make sure your cache strategy is dressed to impress, and ready to go.

Homework time!

Keep yourself in the loop with jQuery documentation and keep exploring other libraries to swim above the caching undertow.