2014-11-23 16 views
7

Quindi sto utilizzando Google Volley per la richiesta HTTP, che in pratica utilizza .Android (Java) HttpURLConnection ritentivo silenzioso su timeout 'lettura'

Secondo le mie prove, il problema è questo :
Quando la 'lettura' timeout sulle HttpURLConnection raggiunge, un secondo tentativo silenzioso viene eseguito prima che la connessione è chiusa e l'eccezione relativa gettato (SocketTimeoutException).

Nota che:
- Ho notato questo errore quando si utilizza HTTP POST richiesta.
- Il timeout 'lettura' è diverso dal timeout 'connect'.
- Se il timeout di 'lettura' (impostato chiamando connection.setReadTimeout(int)) NON è impostato su (0) o impostato su un valore superiore a connection.setConnectTimeout(int), questo errore non si verifica.
- Questo problema è stato discusso, ad esempio here, ma non ho trovato alcuna soluzione soddisfacente.
- Una questione in qualche modo correlato può essere trovato here, ma non sono sicuro che è rilevante

Più Sfondo
mia app viene utilizzata per pagare i soldi, quindi non ritentare la richiesta è (è?) fondamentale (sì, so che può essere gestito dal server, voglio comunque che il mio cliente sia "corretto").

Quando viene impostato il timeout di 'lettura', nel caso in cui la connessione al server sia stabilita, ma il server attende/dorme/fa ritardare-risposta quel tempo di "timeout" prima di rispondere (sollevando così l'eccezione di 'lettura' e non il ' connect 'exception), un'altra richiesta (silenziosa) viene inviata appena prima che tale eccezione venga sollevata, risultando in 2 richieste simili, che non sono accettabili.

Che tipo di soluzione sto cercando?
Bene, uno che risolverà bene questo problema/bug, proprio come la correzione spiegata here (ma, ancora una volta, penso che sia irrilevante in questo caso).
Inoltre, vorrei mantenere il flusso originale così com'è, ovvero non forzare la chiusura della connessione o qualcosa del genere.

Quello che sto per fare ora è impostare il timeout di "lettura" su due volte il timeout della "connessione" (iniziano a contare allo stesso tempo), per assicurarsi che l'eccezione di "connessione" venga sollevata per prima. Cercherò anche di superare questo problema sul lato server. Il problema è che questo timeout di 'lettura' esiste per un motivo, e la mia attuale implementazione praticamente la ignora e gestisce solo i timeout di 'connessione'.

EDIT Il Volley biblioteca di RetryPolicy non ha alcun effetto su questo tema, in quanto questo è un nuovo tentativo silenzioso. Ho cercato il più profondo possibile all'interno della biblioteca. Registri/punti di interruzione in tutto il mondo, ha annullato le chiamate per riprovare. Quello che so è il 99,99% di un problema HttpURLConnection.

+0

erano si in grado di risolverlo? –

+0

Non è una soluzione perfetta, ma come ho detto, quando sto facendo ora, è impostato il timeout di 'lettura' a uguale o due volte il timeout della 'connessione'. Risponderò alle altre persone per vedere facilmente questa soluzione. –

risposta

5

Questa cattiva decisione è stata presa da uno sviluppatore nel 2006. Ecco una bella citazione di qualcuno che spiega tutta la situazione dal punto di vista java:

"Come probabilmente avete indovinato ormai è un bug (http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6382788) .Non il meccanismo dei tentativi, ovviamente, è solo una schifezza. Il bug è che accade anche per un POST (che non è idempotente per HTTP RFC). Ma non preoccupatevi, Bill ha corretto quel bug a lungo tempo fa, Bill lo aggiustò introducendo un interruttore, Bill apprese della compatibilità con le versioni precedenti, Bill decise che era meglio lasciare l'interruttore "attivo" di default perché ciò avrebbe reso il bug-back-compatibile. "Bill sorride. di gli sviluppatori sorpresi in tutto il mondo si sono imbattuti in questo. Si prega di non essere come Bill "
Source

Beh, la soluzione proposta è:?!

System.setProperty("sun.net.http.retryPost", "false") 

ma non possiamo fare questo su Android L'unica soluzione rimasta allora è:

httpURLConnection.setChunkedStreamingMode(0); 

Which seems to be working, but isn't very effective from a requesting-time perspektive.

EDIT: Non ho potuto utilizzare questa implementazione, quindi ho cercato una libreria alternativa. Ho scoperto che l'implementazione di HttpUrlConnection utilizza OkHttp da Android 4.4. Siccome OkHttp è opensource, potrei cercare se hanno anche problemi con i tentativi silenziosi. E loro lo hanno had problems with it e lo hanno risolto nell'aprile 2016. CommonsWare (un vero android expert) spiega che ogni produttore può decidere quale implementazione possono usare. Di conseguenza, ci sono molti dispositivi là fuori che eseguono silenziosi tentativi su richieste POST e come sviluppatore possiamo provare solo alcuni workarround.

La mia soluzione sarà quella di cambiare la libreria

EDIT 2: Per darvi una risposta definitiva: You can now use OkHttp as the transport layer for Volley with minimal code.

Another helpful solution

+0

Quindi ... 'httpURLConnection.setChunkedStreamingMode (0)' non comporterà tentativi? Per favore spiegate l'effetto nella risposta :) E sì, totalmente il tipo di risposta che mi sarebbe piaciuto sentire ... –

+1

Ho avuto problemi con la soluzione proposta, quindi ho modificato la risposta. – oli

+0

Si prega di aggiungere un collegamento alla mia risposta qui sotto. Suppongo che possa ancora aiutare gli altri ... grazie. –

0

È possibile verificare la classe DefaultRetryPolicy di Volley.

+1

Thx, ma questo problema è più profondo. La prima cosa che ho controllato è stata la politica dei tentativi, e l'ho cancellata. Questo tentativo è silenzioso, quindi Volley non ne sa nulla. –

3

Bene, è trascorso molto tempo, quindi ho pensato di rispondere con la mia attuale (non perfetta) soluzione per le altre persone per vederlo facilmente (scritto anche all'interno della domanda).

Basta impostare readTimeout su 0 (nessun timeout) o almeno sul valore di timeout della connessione. Ciò assicurerà che il timeout della connessione verrà aumentato prima del timeout di lettura.

int timeoutMs = request.getTimeoutMs(); // or whatever 
connection.setConnectTimeout(timeoutMs); // actual timeout desired 
connection.setReadTimeout(timeoutMs);  // >= timeoutMs or 0 

Naturalmente, dipende dall'utilizzo della richiesta. Il più delle volte, l'app fa parte di un progetto che contiene il relativo server, e sai che i timeout di lettura non dovrebbero accadere comunque ..

Come detto, non proprio una "soluzione", ma molto bella e 90% correzione utile.