4

Problem:

After leaving a page that uses pushState and popState to handle back and forward navigation when retrieving HTML and JSON from the same base URL, returning to the page using the back button shows the cached JSON instead of the HTML.

Description:

  1. Using Ajax calls to page through search results in our application using the same URL as page URL, but with format=json.
  2. On each page a window.history.pushState(state,null,url) is called.
  3. popState is used internally when the back and forward buttons are used within this page.
  4. Results have links that load other pages. (This application is not a SPA)
  5. After clicking on one of these links and then clicking the 'Back' button, Chrome shows the JSON stored in the state and not the previous page with a console error:

Resource interpreted as Document but transferred with MIME type application/json

Firefox and Safari correctly reload the page and since I am updating the URL in the pushState call they correctly reload the page to the state I wish (i.e. the url has the correct page identification and, therefore, reloads the correct page of the search results).

Tom Talbott
  • 147
  • 8

1 Answers1

5

Looks like the answer was turning off caching of the JSON or convincing Chrome that the cached JSON wasn't what was wanted. Based on another question's answer, I added response.headers['Vary'] = 'Accept' in the rails controller when returning JSON.

So, in context:

respond_to do |format|
  format.html do 
    render :template => xxx
  end
  format.json do
    response.headers['Vary'] = 'Accept'
    render :json => {...}
  end
end

Questions that helped me:

Tom Talbott
  • 147
  • 8
  • I don't use Rails, but I had a similar problem and this helped. Thanks! I found this explanation of the `Vary` header helpful: https://stackoverflow.com/a/1975924/1079869 – Matias Kinnunen Jun 15 '20 at 13:10
  • Indeed: setting "Vary:Accept" tells Chrome that there is a possibility that this url returns various "Content-Type"'s. So this setting on server side fixes it. – Julesezaar Jan 12 '21 at 19:23
  • In PHP, I added `header('Vary: Accept');` right before I return all JSON, and boom! it worked. Thanks. – HartleySan Jan 12 '21 at 21:49