Devember 2016 – Day 8 and 9 – Chrome Caches AJAX Response

I didn’t blog yesterday here, but I did tweet, and I did write code.  It was late, but I still got stuff done.

Today was an interesting day.  I’m still coding, but I came across an interesting bug I’d like to share.

So, in the code I have now, depending on the request’s Accept header, it will return either HTML or JSON.  It’s the same endpoint, but depending on the request made, it will return different results.  The result is the same information, just presented differently.  One way for humans, another for computers.

Now, in Firefox and Safari, this works just fine.  If you go to the page, everything loads up as you’d expect.  If you go back in the browser, and then go forward again, the page that is displayed is the same page you’d expect to see.  The HTML result.

But in Chrome, it doesn’t work like this.  Here is what happens in my case.

First, you make a request to a page /foo/bar.  This request has a header entry:

Accept: text/html

The page loads an HTML page which has JavaScript.  This JavaScript makes a request to the same page /foo/bar, except this time, the Accept header is different.

Accept: application/json

In this case, it’s the same URL, but different requests.  This second request returns JSON as expected.

Now, you click the Back button, and go back a page.  Then you click the Forward button, and instead of seeing the HTML page as you’d expect, you see the JSON result.

Now, even though Chrome has this bug, you can work around it.  When you return the JSON response, you can just send back a response that includes the following headers.

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Expires: Thu, 18 Nov 1971 01:00:00 GMT

This will prevent the AJAX response from being cached, meaning the last cached item will be the HTML page.

How else can you use this?

So, in thinking about this, I was wondering how else I could use this.  After all, if I make a request to the same URL behind the scene and cache it, I can change what’s cached in the browser.  Is there ever a case where you’d want to change what was cached without showing the user right away? I don’t know.  But it’s interesting.  And it would only work on Chrome.