2012-03-14 16 views
9

Considerate questo punto di vista Django che otterrà un elenco di elementi associati all'utente corrente:Qual è il modo migliore per gestire i timeout delle sessioni nelle richieste Ajax?

@login_required 
def list_items(request, page_number=0): 
    items = Paginator(request.user.items, 5).page(page_number).object_list 
    return HttpResponse(cjson.encode(items)) 

Ovviamente, vuole utilizzare il login_required decoratore, per limitare l'accesso alla visualizzazione per gli utenti registrati.

Cosa fa quando un utente non autenticato tenta di accedere alla vista? Restituisce un HttpResponseRedirect verso settings.LOGIN_URL.

Considerate questo codice JavaScript, che chiama la vista:

var getPage = function(pageNumber) { 
    $.ajax({ 
     url: "/list_items/" + pageNumber + "/", 
     success: function(data) { 
      $("#list_container").html(formatData(data)) 
     } 
    }); 
}; 

Supponiamo settings.SESSION_COOKIE_AGE = 60 secondi.

Se un utente va a pagina 1, lo legge per 61 secondi, poi clicca sul pulsante per la pagina 2, login_required decoratore di Django rileverà che la sessione non è più attivo, e restituirà un HttpResponseRedirect(settings.LOGIN_URL), che farà sì che il success callback per ottenere una pagina di accesso HTML anziché l'elenco codificato JSON.

This is where it happens.
It's called by user_passes_test here.

Qual è il modo migliore per gestire questa situazione?

Ecco un paio di cose che ho pensato di:

1. Il success callback deve controllare la risposta, e vedere se ottiene una pagina di accesso, con qualsiasi mezzo (controllare se il tipo di contenuto è html, controllare i contenuti , eccetera). Ma questo significa che dobbiamo avvolgere tutte le chiamate AJAX con un wrapper di richiamata in questo modo:

$.ajax({ 
     url: "/list_items/" + pageNumber + "/", 
     success: sessionExpiryCallbackWrapper(function(data) { 
      $("#list_container").html(formatData(data)) 
     }) 
    }); 

Ma questo è brutto, e gli sviluppatori potrebbe dimenticare di fare questo in tutto il mondo.

2. Utilizzare $.ajaxComplete per gestire tutte le richieste.

$.ajaxComplete(globalCompleteCallback); 
    $.ajax({ 
     success: successCallback, 
     complete: completeCallback 
    }); 

Ma questo è l'ordine di chiamata:

successCallback(); // success is called before complete 
    completeCallback(); 
    globalCompleteCallback(); // this is called after the local callback 

Così abbiamo solo prendere il reindirizzamento, dopo successCallback ha fallito, e possibilmente con JS errori a causa dei dati non validi ricevuti.

3. Se login_required sarebbero tornati 403 sulle richieste AJAX:

if not user.is_authenticated(): 
     if request.is_ajax(): 
      # send 403 to ajax calls 
      return HttpResponse403("you are not logged in") 
     else: 
      # regular code path 
      return HttpResponseRedirect(settings.LOGIN_URL) 

Ma login_required utilizza solo user_passes_test che non fa questo.

user_passes_test ha un sacco di funzionalità, quindi non è una buona idea reimplementarlo.

Qual è il modo migliore per gestire i timeout per le chiamate AJAX?

+1

Scusate ma ho intenzione di diventare tutto filosofico su di voi. Lo scopo originale dei timeout delle sessioni era impedire al server di conservare risorse significative o dover eseguire operazioni costose per ogni richiesta. Ora abbiamo strutture client-side che eseguono la maggior parte del lavoro. Quindi perché sono necessari anche brevi timeout di sessione? –

+0

@DaveMethvin I timeout della sessione sono necessari per restringere la finestra per il dirottamento della sessione sia a) sul filo/aria o b) fisicamente da qualcuno che accede al computer di qualcun altro dopo che è passato un po 'di AFK. – Prody

+1

Questo problema sembra abbastanza facile da risolvere, basta avere i timeout della sessione del client più brevi di quelli del server. In questo caso, dovrebbe essere davvero raro che il client effettui una richiesta che si trova su un server senza una sessione valida. Inoltre, ciò significa che puoi creare un messaggio "la tua sessione è scaduto" avviato dal cliente. –

risposta

5

Lo gestivo avendo il tuo metodo di timeout della sessione per verificare se è stato richiesto o meno con AJAX. Se è ajax, restituire uno 401 non autorizzato (o 403 vietato o qualunque stato abbia senso) codice di stato con una stringa json vuota. Successivamente, nel tuo javascript, associa un gestore globale ajaxError che controlla il codice di stato e lo gestisce in modo appropriato.

+1

Questo è quello che ho fatto alla fine, ma ho dovuto scrivere un nuovo decoratore 'login_required' per restituire HttpResponse40 {1,3} se request.is_ajax() else RedirectToLoginPage()' piuttosto che semplicemente reindirizzare in entrambi i modi. – Prody

0

È possibile utilizzare qualcosa come http://amplifyjs.com/ che consente di scrivere un buon wrapper per le chiamate AJAX e quindi utilizzare la sua funzione data mapping per verificare se l'utente è ancora connesso prima di effettuare la chiamata AJAX.

In questo modo è possibile avere un timer sul lato client che imposta l'utente sullo stato di disconnessione e fornisce un suggerimento in modo che il controllo di accesso non debba essere eseguito prima di ogni chiamata AJAX.

In alternativa è possibile utilizzare un numero personalizzato decoder che richiede all'utente di accedere e riprovare la chiamata AJAX se l'utente è stato disconnesso. Avrebbe bisogno di memorizzare tutti i dati xhr e le richiamate con cui viene chiamato fino a quando l'utente effettua il login.

Problemi correlati