2015-09-02 27 views
5

Sto usando la libreria okhttp nella mia applicazione Android con diverse richieste asincrone. Tutte le richieste richiedono che il token sia impostato nell'intestazione. A volte ho bisogno di aggiornare quel token usando RefreshToken, quindi decido di usare la classe Authenticator di OkHttp.Multithreading autenticatore Okhttp

Cosa succede quando 2 o più richieste asincrone ricevono il codice 401 dal server all'incirca nello stesso momento? Sarebbe il metodo del Authenticator

@Override 
public Request authenticate(Proxy proxy, Response response) throws IOException 
{     
    return null; 
} 

essere chiamato per ogni richiesta, o sarà chiamato solo una volta per prima richiesta, che ha ottenuto 401?

Come aggiornare il token una sola volta?

risposta

1

Vedo qui due scenari basati su come funziona l'API che chiamate.

Il primo è decisamente più semplice da gestire: la chiamata di nuove credenziali (ad esempio token di accesso) non ha scadenza vecchia. Per ottenerlo è possibile aggiungere un contrassegno aggiuntivo alle proprie credenziali per dire che le credenziali vengono aggiornate. Quando hai una risposta 401, imposta flag su true, fai una richiesta per ottenere nuove credenziali e le salvi solo se flag è uguale a true, quindi verrà gestita solo la prima risposta e il resto verrà ignorato. Assicurati che il tuo accesso al flag sia sincronizzato.

Un altro scenario è un po 'più complicato: ogni volta che si chiamano nuove credenziali, una vecchia è impostata per essere scaduta dal lato server. Per gestirlo, introdurrei il nuovo oggetto come semaforo: esso verrebbe bloccato ogni volta che "le credenziali vengono aggiornate". Per assicurarti di effettuare solo una chiamata di 'aggiornamento credenziali', devi chiamarla in un blocco di codice che è sincronizzato con il flag. Può sembrarlo:

synchronized(stateObject) { 
    if(!stateObject.isBeingRefreshed) return; 
    Response response = client.execute(request); 
    apiClient.setCredentials(response.getNewCredentials()); 
    stateObject.isBeingRefreshed = false; 
} 

Come hai notato c'è un controllo supplementare if(!stateObject.isBeingRefreshed) return; per annullare la richiesta di nuove credenziali seguenti richieste che hanno ricevuto 401 risposte.

+0

In questo modo, si perdono le richieste che vengono restituite, non è vero? Con il modo in cui metto di seguito, puoi chiamare di nuovo quelle richieste. – antonicg

+0

Quale scenario intendi? Se il server non ha scaduto il vecchio token di accesso quando ne viene generato uno nuovo, non è necessario bloccarlo e non è un problema quando ne perdiamo uno perché avremo ancora un token di accesso che funziona. Ovviamente difende il modo in cui funziona il tuo sistema. In un secondo scenario ho descritto come evitare di richiamare più richieste di "aggiornamento dei token di accesso" in primo luogo (il blocco sincronizzato impedirà di farlo), quindi nulla andrà perso. –

+0

È vero, se il server non scade il vecchio accesso non è necessario per bloccare le vecchie richieste. Grazie per l'approvazione. – antonicg

1

Nel mio caso ho implementato lo Authenticator utilizzando il modello Singleton. È possibile sincronizzare il metodo authenticate. Nella sua implementazione, controllo se il token della richiesta (ottenendo l'oggettoricevuto nei parametri del metodo di autenticazione) sia lo stesso salvato nel dispositivo (salvi il token in un oggetto SharedPreferences).

Se il token è uguale, significa che non è stato ancora aggiornato, quindi eseguo di nuovo l'aggiornamento del token e la richiesta corrente.

Se il token non è uguale, significa che è stato aggiornato in precedenza, quindi eseguo di nuovo la richiesta ma utilizzando il token salvato nel dispositivo.

Se hai bisogno di ulteriore aiuto, ti prego di dirmelo e inserirò del codice qui.

+1

Penso che sarebbe opportuno aggiungere informazioni che il token deve essere salvato con il metodo "commit" invece di "apply" per renderlo sincrono. –

+0

Sì @KrzysztofSkrzynecki, buon punto. Ho dimenticato di notare questo. – antonicg

+0

Ciao @antonicg. Potete fornire qualche codice? Sto cercando di trovare un modo per gestire le istanze in cui thread diversi possono tentare un aggiornamento allo stesso tempo. Sembra che la tua risposta possa risolvere il mio problema, ma la sincronizzazione è dove sono bloccato e non capisco. – JPM