9

Si noti che non penso che questo problema sia correlato a Backbone o JavaScript ma è necessario includere alcuni codici Backbone come contesto sul problema.Viene fornita una risposta direttamente dalla cache quando si fa clic sul pulsante Indietro

il relativo codice

Ho un client-side Backbone router con un percorso che prende un parametro chiamato contactId. Sembra simile a questo:

Backbone.Router.extend({ 

    routes: { 
    "jobs/new?contact_id=:contactId": "newForContact" 
    }, 

    // Fetch the contact and initialize a new job model which 
    // is associated with that contact. 
    newForContact: function(contactId) { 
    var contact = new Contact(id: contactId); 
    contact.fetch({ 
     success: _.bind(function(model, resp) { 
     var job = new Job(contact: contact); 
     this.new(job); 
     } 
    }, this)); 
    }, 

    // Show the JobView for the given job. 
    new: function(jobModel) { 
    view = new JobView(job: jobModel); 
    $('body').append(view.render().el); 
    } 
}; 

Ora sto cercando di usare questa impostazione con pushState acceso.

Quando si preme il percorso che attiva il percorso newForContact, tutto funziona come previsto. Tuttavia, se premo il pulsante Indietro del browser a questo punto, mi viene servita la risposta JSON dal metodo contact.fetch() direttamente dalla cache del browser. Nessuna richiesta viene inviata al server.

fetch JSON response

I registri App

Si può vedere questo nei ceppi app Rails. In questa parte, visito il percorso che fa scattare newForContact.

Started GET "/jobs/new?contact%5Bid%5D=1&contact%5Btype%5D=Customer" for 127.0.0.1 at 2012-10-31 22:41:48 +0000 
Processing by JobsController#new as HTML 
    Parameters: {"contact"=>{"id"=>"1", "type"=>"Customer"}} 
    User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]] 
    Business Load (0.3ms) SELECT "businesses".* FROM "businesses" WHERE "businesses"."id" IN (1) 
    Rendered shared/_search_form.html.erb (0.3ms) 
    Job Load (0.4ms) SELECT "jobs".* FROM "jobs" WHERE "jobs"."business_id" = 1 ORDER BY created_at desc 
    Rendered jobs/_list.html.erb (1.5ms) 
    Rendered jobs/index.html.erb within layouts/application (4.1ms) 
    Rendered layouts/_head_content.html.erb (0.7ms) 
    Rendered layouts/_flash.html.erb (0.0ms) 
Cache read: views/jobs/main_nav/d6a805d9b6f285e424f207add4f35595 
Read fragment views/jobs/main_nav/d6a805d9b6f285e424f207add4f35595 (0.4ms) 
    Rendered layouts/_nav.html.erb (0.6ms) 
    Rendered layouts/_header.html.erb (0.7ms) 
Completed 200 OK in 12ms (Views: 8.0ms | ActiveRecord: 1.0ms) 
Cache read: http://print.dev/customers/1? 

Si può vedere che recupera il contatto a questo punto con una richiesta JSON.

Started GET "/customers/1" for 127.0.0.1 at 2012-10-31 22:41:48 +0000 
Processing by CustomersController#show as JSON 
    Parameters: {"id"=>"1"} 
    User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]] 
    Business Load (0.4ms) SELECT "businesses".* FROM "businesses" WHERE "businesses"."id" IN (1) 
    Customer Load (0.2ms) SELECT "customers".* FROM "customers" WHERE "customers"."business_id" = 1 AND "customers"."id" = $1 LIMIT 1 [["id", "1"]] 
    CustomerEmployee Load (0.3ms) SELECT "customer_employees".* FROM "customer_employees" WHERE "customer_employees"."employer_id" IN (1) 
    Job Load (0.4ms) SELECT "jobs".* FROM "jobs" WHERE "jobs"."contact_type" = 'Customer' AND "jobs"."contact_id" IN (1) 
    Invoice Load (0.3ms) SELECT "invoices".* FROM "invoices" WHERE "invoices"."client_id" IN (1) 
    Job Load (0.5ms) SELECT "jobs".* FROM "jobs" WHERE "jobs"."contact_id" = 1 AND "jobs"."contact_type" = 'Customer' AND "jobs"."state" = 'finished' AND "jobs"."invoice_id" IS NULL 
    Rendered customers/show.json.rabl (2.8ms) 
Completed 200 OK in 67ms (Views: 3.2ms | ActiveRecord: 2.5ms) 

A questo punto, premo il pulsante Indietro del browser ma nessuna nuova richiesta viene registrata sul server.

Rails Ambienti

Ciò accade soltanto sul mio server di gestione temporanea (Heroku), non è in fase di sviluppo. Posso ricrearlo localmente eseguendo l'app con Pow nell'ambiente di staging che ha attivato la memorizzazione nella cache nelle configurazioni di rails.

config.action_controller.perform_caching = true 

Si noti che anche con la memorizzazione nella cache attivata, non riesco a ricreare il bug nell'ambiente di sviluppo.

Questo problema si verifica in Chrome 22.0.1229.94, FF 16.0.2 e Safari 6.0.1. Uso Rails 3.2.8.

Domande possibilmente correlate

It seems like this guy was having a very similar problem to me.

campione dal vivo

Se davvero si vuole è possibile visualizzare il problema in diretta sul mio server di gestione temporanea su Heroku.

Step to Repro (edit: questi non funzionano più da quando ho corretto il problema).

  1. Login here con la posta elettronica: [email protected] e passare: foobar
  2. Visita http://print-staging.herokuapp.com/customers/2. Dovresti vedere una finestra di dialogo che sembra incasinata.
  3. Fare clic sul piccolo collegamento "Nuovo lavoro" nella finestra di dialogo. La pagina dovrebbe cambiare e dovrebbe aprirsi una nuova finestra di dialogo.
  4. Fare clic sul pulsante Indietro del browser.

risposta

9

È possibile aggiungere un'intestazione no-cache per la tua risposta sul lato server, questo dovrebbe indicare al browser per non memorizzare nella cache la risposta:

response.headers["Cache-Control"] = "no-cache" 
+1

Ok ma perché devo farlo? In realtà voglio che il browser memorizzi la risposta nella maggior parte dei casi (probabilmente non cambierà molto). Non voglio che il pulsante Indietro mostri la risposta in cache. Penso che fondamentalmente voglio inviare una richiesta JSON ma poi quando l'utente preme il pulsante Indietro, voglio fare una richiesta HTML piuttosto che una richiesta JSON. –

+0

scusa non capisco cosa intendi David ... come vuoi usare il caching ma non vuoi che il pulsante back mostri la risposta in cache? – kabaros

+0

Suppongo di aver bisogno di un modo per ottenere la richiesta JSON GET di non inserire una voce nello stack della cronologia dei browser (nonostante io stia usando 'pushState' con Backbone. In questo modo potrei premere il pulsante Indietro e saltare sopra la richiesta JSON e mostrare all'utente la richiesta precedente a quella (questa sarebbe una richiesta HTML dovrebbe essere in grado di formare una pagina effettiva per mostrare all'utente). Forse questo è impossibile, non sono sicuro? –

2

non sto usando Backbone, questo è proprio quello che ho fatto con AJAX/pushState


io uso history.pushState() nelle mie risposte AJAX.

var url = "http://foo.com/path/to/page"; 
var relative_url = UrlToRelative(url); // some function to convert a URL to relative 
var absolute_url = UrlToAbsolute(url); // some function to convert a URL to absolute 
history.pushState(
    { 
    hash: "#"+relative_url, 
    title: document.title, 
    initialHref: absolute_url 
    }, 
    document.title, 
    url 
); 

e ho un listener di eventi per onPopState:

window.onpopstate = function(event) { 
    if (event.state && event.state.initialHref) { 
    $.ajax({ 
     complete: null, 
     data: {}, 
     dataType: "script", 
     success: null, 
     type: 'GET', 
     url: event.state.initialHref 
    }); 
    } 
} 

Questo listener di eventi effettua una richiesta AJAX. L'unico problema è che lo schermo impiega alcuni secondi per cambiare quando si torna alle pagine che impiegano alcuni secondi per ottenere una risposta del server. E non c'è spinner o indicatore di progresso occupato.