2013-05-06 6 views
10

Folks, Ho un'applicazione web in cui ho riutilizzato lo stesso percorso per le rappresentazioni JSON e HTML della stessa risorsa, chiamiamolo/foo/dettagli per ora. Questa pagina è collegata da, chiamiamola/bar/dettagli. (quindi, guardando/bar/dettagli vedi link a ->/foo/dettagli).Pulsante Indietro (Chrome) Ottiene Json invece di HTML in Play Framework

Quando passo dalla prima alla seconda, tutto funziona correttamente. Quando faccio clic sul pulsante Indietro in Chrome, la pagina originale viene visualizzata come JSON anziché HTML. Se clicco nel refresh del browser, ottengo la rappresentazione HTML e non il JSON.

Ecco il codice che sto usando per rilevare 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) 

Questa è l'implementazione standard di questo modello e funziona ovunque, tranne quando uso il pulsante indietro in Chrome in alcuni situazioni.

C'è qualche valore che non sto cancellando, o qualcosa che le mie pagine stanno facendo con Ajax che confonde Play per renderlo renderizzato in Json, o forse Chrome sta memorizzando nella cache la pagina ma memorizzando nella cache l'intestazione sbagliata accetta ??

Posso aggirare questo usando due percorsi diversi, uno per Json e uno per Html, ma non mi piace perché mi sembra di arrendermi.

Qualcuno ha qualche idea su cosa provoca questo comportamento solo nel pulsante Indietro?

+0

Potrebbe essere una cache del browser. Hai provato su diversi browser? –

+0

È sicuramente la cache del browser di Chrome. –

risposta

2

Era decisamente la cache del browser di Chrome. Non fa distinzione tra una richiesta fatta a/foo/bar con "Accetta" -> "applicazione/json" e con l'intestazione HTML accettata. Di conseguenza, caricherò la pagina HTML, il JavaScript su quella pagina avrebbe colpito lo stesso URL per i dati JSON non elaborati, e poi la prossima volta che torno indietro, Chrome pubblicherebbe il JSON memorizzato nella cache invece dell'HTML memorizzato nella cache.

Di conseguenza, ho dovuto modificare i miei percorsi in modo che tutte le mie API JSON/REST passino attraverso URL diversi in modo che Chrome (e Safari) non memorizzino nella cache il JSON.

+0

Non sono sicuro se avrebbe funzionato, ma avresti potuto impostare un'intestazione sulla risposta JSON per dire al browser di non metterlo nella cache. – estmatic

+0

@estmatic se sei interessato, vedi la mia risposta, se invii un header "Vary: Accept" nella risposta, risolverà il problema. – jay

22

Kevin, hai ragione. Tuttavia, c'è un'altra soluzione.

Se si aggiunge "Vary: Accept" all'intestazione della risposta, questo farà sì che Chrome e altri browser con questo problema (ad es. Firefox v 21) distinguano tra cache json e html. NOTA: Variabile: l'intestazione Accept-Encoding non funziona, per quanto ho provato.

Se si utilizza nginx, è possibile impostare questo: http://wiki.nginx.org/HttpProxyModule#proxy_set_header

proxy_set_header Vary Accept;

Tuttavia, v'è un problema con nginx dove il variare accettare intestazione non saranno inviati a volte, qualcosa a che fare con la cache. Vedi http://wiki.nginx.org/HttpProxyModule#proxy_set_header Per risolvere questo problema, puoi attivare gzip_vary per nginx, ma invierà Vary: Accept-Encoding header. Questa intestazione non risolve il problema.

Io uso rotaie, e ho usato un before_filter in cui ho modificato response.headers["Vary"]= "Accept"

Sono sicuro che ci sono altri modi di fare questo con altri server/quadri.

Altre informazioni: https://web.archive.org/web/20130114082345/http://blog.sdqali.in/blog/2012/11/27/on-rest-content-type-google-chrome-and-caching/

+0

Questa dovrebbe essere la risposta accettata, sicuramente ha fatto il trucco per me. –

+0

buono a sapersi Patrick :) – jay

Problemi correlati