2010-08-27 10 views
35

Ho bisogno di un metodo per monitorare le sessioni di modifica degli utenti e una delle soluzioni che sto esaminando mi farà utilizzare un evento unload per inviare una richiesta Ajax per informare il server della fine della sessione di modifica. (Vedere: Monitoring User Sessions to Prevent Editing Conflict)L'evento di scaricamento può essere utilizzato per attivare in modo affidabile una richiesta Ajax?

La mia lettura (piuttosto limitata) sull'evento unload indica che i codici associati a questo gestore devono essere eseguiti rapidamente e, in quanto tale, viene solitamente utilizzato per la cancellazione di oggetti per evitare perdite di memoria.

La mia domanda è, può funzionare in modo abbastanza affidabile per questo scopo?

PS. Conosco l'opzione async: false.

risposta

35

Questo metodo è abbastanza affidabile, se il server è abbastanza veloce da rispondere. Però qualcosa a cui prestare attenzione. Se chiudi il browser e invii la richiesta AJAX all'evento di scaricamento, è molto probabile che la risposta non venga ripristinata dal server in tempo prima che l'oggetto della finestra venga distrutto. Quello che succede in questo caso (almeno con IE) è che orfana il tuo oggetto di connessione e non lo chiude correttamente fino a quando non viene raggiunto il timeout della connessione. Se il tuo server non ha la connessione keep-alive attivata, dopo aver chiuso 2 finestre (lasciando aperta un'altra finestra), le connessioni aperte al server saranno esaurite (per IE6-7, per IE8 - 6 windows) e non sarai in grado di aprire il tuo sito web fino a quando non verrà raggiunto il timeout della connessione.

Mi sono imbattuto in una situazione del genere prima che stavo aprendo una finestra popup che inviava una richiesta AJAX allo scaricamento, era molto affidabile, ma era afflitta dall'emissione sopra descritta, e ci è voluto davvero molto tempo per per rintracciarlo e capire cosa sta succedendo. Dopo ciò, ho fatto in modo che la finestra di apertura avesse lo stesso codice per chiamare il server, e su ogni scaricamento controllato per l'apertura e il codice lì eseguito se fosse presente.

Sembra che se si chiude l'ultima finestra del browser, IE distruggerà correttamente la connessione, ma se un'altra finestra è aperta, non lo farà.

P.S. E solo per commentare la risposta sopra, AJAX non è veramente asincrono. Almeno l'implementazione di JS non lo è. Dopo aver inviato una richiesta, il codice JS sta ancora aspettando la risposta dal server. Non bloccherà l'esecuzione del codice, ma dal momento che il server potrebbe impiegare un po 'di tempo per rispondere (o abbastanza a lungo per consentire a Windows di terminare l'oggetto della finestra di IE), probabilmente si verificherà il problema descritto in precedenza.

+1

Qualcuno ha provato questo con async disattivato? Immagino che ciò impedirebbe al browser di scaricare fino al ritorno della richiesta. –

+3

Questo è corretto. Con async spento il browser attenderà la risposta dal server prima di scaricare la pagina. Questo aiuta con bug di Chrome, dove Chrome è molto inaffidabile quando si tratta di scaricare eventi e operazioni asincrone. Questo risolverà anche la connessione IE che ho descritto sopra. Ma sarà visibile all'utente. –

+2

Vale la pena tenere d'occhio la nuova API Beacon con 'Navigator.sendBeacon' che consentirà un modo migliore per inviare in modo affidabile una richiesta asincrona al nostro server allo scaricamento: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon – Wildhoney

1

Dovrai fare i tuoi test sul fatto che il tuo scenario particolare funzioni o meno con il tempo che hai in unload, ma rendere la richiesta AJAX è piuttosto veloce, dal momento che AJAX è asincrono. Basta inviare la richiesta e il gioco è fatto! (Forse dovrai cancellare l'oggetto richiesta appena creato, però.)

Se volevi verificare che la richiesta AJAX l'avesse effettuata, dovresti preoccuparti di più/usare l'opzione async:false (come this discussion) indica). Ma, solo l'invio è un'operazione rapida "boom-and-hai-fatto".

+1

Beh, non voglio chiamarlo affidabile se non può raggiungere il server, giusto? ;) –

+1

Vero, ma pensavo volessi dire affidabile in quanto il browser effettivamente invierà la richiesta. – palswim

3

Abbiamo un caso in cui ne avevamo bisogno. È una pagina di report che ha bisogno di una memoria seria sul server, quindi volevamo liberarla immediatamente non appena uscivano dalla pagina. Abbiamo creato un set di frame e aggiunto l'handler di download lì. Il modo più affidabile era quello di impostare lo src di un'immagine sullo script di liberazione. Abbiamo effettivamente utilizzato sia lo scaricamento che onbeforeunload per la compatibilità tra browser. Non ha funzionato nei web kit nightly ma la gestione è stata OK con quello.

Tuttavia, questa non era la mia soluzione proposta. Userei un approccio heartbeat che richiede più lavoro ma è molto più robusto.

La tua pagina dovrebbe inviare richieste periodiche di heartbeat. Ogni richiesta imposta l'ultimo heartbeat da una pagina. È quindi necessario un thread che viene eseguito sul server e cancella la memoria se l'ultimo heartbeat era troppo tempo fa.

Questo non risolve il problema di lasciare la pagina in alto per un lungo periodo. Per questo è necessario un monitoraggio per l'attività dell'utente e lasciare quella pagina dopo un periodo di inattività (assicurarsi di confermare con l'utente)

+0

Hai * davvero * bisogno del metodo "frameset', image e freeing script? Sembra piuttosto hacker ... O era molto più affidabile rispetto all'utilizzo dei due eventi 'scarica '? –

+0

Avevamo bisogno del frameset perché c'era una navigazione in corso all'interno della pagina, volevamo solo inviare la richiesta di "memoria libera" quando ci allontanavamo dal set di pagine. Il metodo image/two-download era il modo in cui lo ottenevamo per funzionare in modo più affidabile su browser e SO. –

12

Hai provato a utilizzare

var i = new Image(1,1); 
i.src='http://...' 

E proprio tornando qualche immagine vuoto dal server. Penso che dovrebbe essere affidabile, lo script bloccherà. BTW: bello aggiungere timestamp per evitare il caching.

+0

Ho trovato che le chiamate AJAX nella funzione evento onload non hanno funzionato, ma questo metodo ha funzionato. Va notato che il codice funzione non si ferma o non blocca lo scaricamento della pagina, il codice può essere eseguito dopo che la pagina è stata scaricata. – nuander

-2

Avevo un caso in cui avevo solo bisogno di notificare al server lo scaricamento e non mi importava della risposta.

Se questo è il vostro caso è possibile ignore_user_abort e poi si sa che succederà "affidabile"