Folks, I've got a web application where I have re-used the same route for the JSON and HTML representations of the same resource, let's call it /foo/details for now. This page is linked from, let's call it /bar/details. (so, looking at /bar/details you see link to -> /foo/details).
When I go from the first page to the second, everything works fine. When I click the back button in Chrome, the original page renders as JSON instead of HTML. If I hit refresh in the browser, I get the HTML representation and not the JSON.
Here's the code I'm using to detect JSON vs HTML:
res.result.map { group =>
render {
case Accepts.Html() => Ok(views.html.groups.details(group))
case Accepts.Json() => Ok(Json.toJson(group))
}
}.getOrElse(NotFound)
This is the standard implementation of this pattern and it works everywhere, except when I use the back button in Chrome in certain situations.
Is there some value I'm not clearing, or something my pages are doing with Ajax that is confusing Play to make it render in Json, or perhaps Chrome is caching the page but caching the wrong accepts header??
I can get around this by using two different routes, one for Json and one for Html, but I dislike that as it feels like I'm giving up.
Anybody have any ideas as to what causes this behavior in the back button only?
Google Chrome Open the Chrome menu and select Settings. Then, select Advanced > Reset and clean up > Restore settings to their original defaults.
For pages that are set as non-cached, the browser reloads the page from the server when you press Back, as though it was the first time you are visiting it. For cached pages, the browser displays it out of the cache, which is much faster.
Kevin you are right. However, there is another solution.
If you add "Vary: Accept" to the response header, it will make chrome and other browsers with this issue (eg Firefox v 21) differentiate between json and html cache. NOTE: Vary: Accept-Encoding header does not work, as far as I have tested.
If you use nginx, you can set this: http://wiki.nginx.org/HttpProxyModule#proxy_set_header
proxy_set_header Vary Accept;
However, there is an issue with nginx where the vary accept header will not be sent sometimes, something to do with the cache. See http://wiki.nginx.org/HttpProxyModule#proxy_set_header To deal with this, you can turn gzip_vary on for nginx, but this will send Vary: Accept-Encoding header. This header does not solve the issue.
I use rails, and I used a before_filter where i modified response.headers["Vary"]= "Accept"
I'm sure there are other ways of doing this with other servers / frameworks.
More info: https://web.archive.org/web/20130114082345/http://blog.sdqali.in/blog/2012/11/27/on-rest-content-type-google-chrome-and-caching/
It was definitely Chrome's browser cache. It makes no distinction between a request made to /foo/bar with "Accept"->"application/json" and with the regular HTML accept header. As a result, I would load the HTML page, the JavaScript on that page would hit the same URL for raw JSON data, and then the next time I hit back, Chrome would serve up the cached JSON instead of the cached HTML.
As a result, I had to modify my routes so that my JSON/REST API all go through different URLs so that Chrome (and Safari) don't cache the JSON.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With