2016-07-14 279 views
7

Diciamo che io sono su/pagina? Id = 1post-reindirizzamento-get (PRG) re-inserisce stessa pagina nella storia nei browser Webkit

Poi ci si dirige verso/pagina? Id = 2

E apporto una modifica a quella pagina, che implementa un post e quindi reindirizza a/page? Id = 2

In Firefox, posso premere il pulsante Indietro una volta e tornare a/page? Id = 1, ma in Chrome e Safari su iPhone, devo premere due volte il pulsante Indietro perché/page? id = 2 si trova nella cronologia del browser due volte. (E se avessi fatto più post da id = 2, avrei dovuto premere il pulsante Indietro tante volte per tornare infine a id = 1)

In alcuni casi, questo sembra un normale comportamento del browser, poiché GET viene semplicemente inserito nella cronologia, ma poiché l'URL è identico alla voce precedente, ciò si traduce in una scarsa esperienza utente, che in genere sembra essere evitata da altre applicazioni Web ... ed è naturalmente evitata in Firefox. Si tratta di un bug inevitabile nei browser Webkit o posso implementare il PRG in un modo diverso per evitare questo?

BTW il comportamento sembra essere lo stesso reindirizzamento con 302 o 303.

UPDATE: Ho preso in giro un po 'di codice di esempio ... non so se c'è una piattaforma come jsfiddle dove potrei caricare questo per voi per vedere in azione:

form.php:

id=<?=$_REQUEST['id']?> 
<form action="submit.php" method="post"> 
<input type="hidden" name="id" value="<?=$_REQUEST['id']?>"> 
<input type="submit" value="submit"> 
</form> 

submit.php:

<?php 
header("Location: form.php?id=" . $_REQUEST['id']); 
die($_REQUEST['id']); 
?> 

Se inizio su form.php? Id = 4 (solo per inserirlo nella cronologia del browser) e poi vai a form.php? Id = 5 e poi premi invio (come se per eseguire una modifica del database), in Firefox ottengo una voce nella storia per ciascuno; in Chrome ottengo una voce per id = 4 e quindi due voci per id = 5. Perché la differenza di comportamento? Penso che il comportamento di Firefox sia migliore, dal momento che colpire due volte per scappare da id = 5 è contro-intuitivo per l'utente.

risposta

1

Anche se non è una spiegazione su cosa succede, ho un modo per aggirarlo che utilizzo in tutte le mie applicazioni. Prima po 'di codice:

form.php sarebbe simile a questa:

id=<?=$_REQUEST['id']?> 
<form action="submit.php" target="iframe" method="post"> 
    <input type="hidden" name="id" value="<?=$_REQUEST['id']?>"> 
    <input type="submit" value="submit"> 
</form> 

submit.php come questo:

<?php 
    header("Location: form.php?id=" . $_REQUEST['id']); 
    die($_REQUEST['id']); 
? 
<script> 
    window.parent.location.reload(); 
</script> 

E' i documenti con alcune cose in più nel tag <form> e una nuova <script> tag.

vorrei anche avere un iframe da qualche parte nel documento come questo:

<iframe name="iframe"></iframe> 

Quindi, per spiegare. Invece di navigare in un nuovo sito e tornare indietro ogni volta che è necessario apportare una modifica, è sufficiente caricare il submit.php in un iframe nel documento esistente. Da qui la parte target="iframe".

Quindi, quando è stato caricato il numero iframe, il che significa che le modifiche sono state apportate, si ricarica la pagina originale per riflettere queste modifiche, quindi la parte window.parent.location.reload();. Poiché la pagina si sta ricaricando, non inserirà una seconda voce nella cronologia.

Spero che questo ha aiutato a voi :)

+0

Grazie. Vedo come funziona, ma wow, approccio piuttosto rotonda, che richiede iframe, javascript, ecc. Per un semplice invio di moduli (e sperando che il browser non inquini la sua storia a causa dell'iframe). Sto ancora sperando che qualcuno possa affrontare i meccanismi alla base del comportamento della cronologia dei browser durante il PRG standard in Webkit e vedere se c'è una soluzione più diretta per affrontarlo. – dlo

+0

Grazie per il bel commento. E sì, sarebbe bello avere una spiegazione reale di come funzionano effettivamente i meccanismi. –

+0

Sì, mi sono rovinato una volta quando ho fatto una domanda su Firefox e qualcuno che è in realtà sul team di sviluppo di Firefox ha risposto. :) – dlo

1

Abbiamo anche sperimentato lo stesso problema e, anche dopo la ricerca per i giorni ho trovato alcuna soluzione "facile". La cosa più vicina che ho trovato è stata questa Webkit Bugzilla ticket, che a prima vista non sembra avere una priorità molto alta. Come hai detto, IE e Firefox si comportano bene.

Dal momento che abbiamo il nostro pulsante Indietro nell'applicazione, siamo stati in grado di risolvere il problema utilizzando la memoria di sessione e controllandola quando la pagina è stata caricata. Il codice dattiloscritto è la seguente:

class DoubleHistoryWorkaround { 

    // key of the attribute we store the URL we where on when clicking on the back button 
    private static comingFromLabel = "comingFromURL"; 
    // key of the attribute of the flag denoting whether we set a valid comingFromURL 
    private static comingFromFlag = "comingFromSet"; 

    constructor() { 
     this.checkLocation(); 
    } 

    /** 
    * Checks the URL we saved in the session and goes a further step back 
    * in the history if the first back button brought us to the same page again. 
    */ 
    private checkLocation() { 
     let doubleEntry : boolean; 
     // have we set a comingFromURL? 
     let comingFromSet = window.sessionStorage.getItem(DoubleHistoryWorkaround.comingFromFlag); 
     if (comingFromSet) { 

      // is the set comingFromURL the same as our current page? 
      let currentURL = window.location.href; 
      let comingFromURL = window.sessionStorage.getItem(DoubleHistoryWorkaround.comingFromLabel); 
      if (currentURL === comingFromURL) { 
       // double history entry detected 
       doubleEntry = true; 

       // before we skip we save our location ourselves, since we might still navigate 
       // to the same page again (in case of triple identical history entries) 
       DoubleHistoryWorkaround.saveLocation(); 

       // skip this page 
       history.back(); 
      } 
     } 

     // reset the location entry unless we just set it ourselves 
     if (!doubleEntry) { 
      this.resetLocation(); 
     } 
    } 

    /** 
    * Saves the current location in the session storage. 
    */ 
    public static saveLocation() { 
     window.sessionStorage.setItem(DoubleHistoryWorkaround.comingFromFlag, "true"); 
     window.sessionStorage.setItem(DoubleHistoryWorkaround.comingFromLabel, window.location.href); 
    } 

    /** 
    * Removes the set location from the session storage. 
    */ 
    private resetLocation() { 
     window.sessionStorage.setItem(DoubleHistoryWorkaround.comingFromFlag, "false"); 
     window.sessionStorage.setItem(DoubleHistoryWorkaround.comingFromLabel, ""); 
    } 
} 

Noi chiamiamo DoubleHistoryWorkaround.saveLocation() quando si clicca sul pulsante Indietro della nostra applicazione, impostare le voci di sessione che vengono controllati da checkLocation().