2013-09-25 16 views
19

Tentativo di utilizzare Volley lib come wrapper di rete per la mia applicazione Android. Ho una connessione attiva e funzionante, ma il problema è che ogni volta che ci sono più intestazioni "Set-Cookie" nella risposta, Volley usa Map che non può avere chiavi duplicate e memorizza solo l'ultima intestazione del Set-cookie e sovrascrive il resto .Volley Android, duplicato Set-Cookie è sovrascritto

Esiste una soluzione alternativa per questo problema?

C'è un'altra lib da usare?

+2

Basta notare questo me stesso, questo è ridicolo da parte di Google. È ovvio che questa libreria è pensata per cose molto leggere. – georgiecasey

+0

Non è un problema con Android Volley. È un problema dei server web. Set-Cookie non può essere multiplo. http://stackoverflow.com/questions/11533867/set-cookie-header-with-multiple-cookies –

+0

http://stackoverflow.com/a/25388897/2819864 è la soluzione più veloce – RominaV

risposta

16

Ho provato le classi eccessive per risolvere questo problema ma quando ho dovuto modificare NetworkResponse, stavo scendendo troppo in basso nella rabbithole. Così ho deciso di modificare direttamente Volley per catturare tutte le intestazioni di risposta in un array e non in una mappa.

La mia forcella è GitHub e ho incluso un example usage activity.

Ho apportato le modifiche a NetworkResponse.java, BasicNetwork.java e HurlStack.java come indicato in this commit.

Poi da utilizzare per le applicazioni attuali si fa qualcosa di simile

protected Response<String> parseNetworkResponse(NetworkResponse response) { 
      // we must override this to get headers. and with the fix, we should get all headers including duplicate names 
      // in an array of apache headers called apacheHeaders. everything else about volley is the same 
      for (int i = 0; i < response.apacheHeaders.length; i++) { 
       String key = response.apacheHeaders[i].getName(); 
       String value = response.apacheHeaders[i].getValue(); 
       Log.d("VOLLEY_HEADERFIX",key + " - " +value); 
      } 

      return super.parseNetworkResponse(response); 
     } 

E 'un piccolo hack sporco ma sembra funzionare bene per me in questo momento.

+1

Sono sorpreso che questo non sia ancora nella versione ufficiale. Sai perché? –

1

È possibile ignorare la classe di volo Network. Potrebbe essere utile esaminare i metodi performRequest e convertHeaders di BasicNetwork. Poi, passando l'implementazione di rete alla contructor di RequestQueue come:

nuovo RequestQueue (nuova NoCache(), nuova YourOwnNetwork());

+0

Ciao @Kazuki, potresti mettere ed esempio? Ho creato la mia interfaccia personale di Network (CustomNetwork) con perfomRequest. Quindi modifico l'implementazione ma non riesco a passare CustomNetwork nel nuovo RequestQueue (...). Potresti aiutarmi? –

3

La prima cosa che è necessario è modificare il metodo BasicNetwork.convertHeaders per supportare più valori di mappa. Ecco esempio di metodo modificato:

protected static Map<String, List<String>> convertHeaders(Header[] headers) { 
    Map<String, List<String>> result = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER); 
    for (int i = 0; i < headers.length; i++) { 
     Header header = headers[i]; 
     List<String> list = result.get(header.getName()); 
     if (list == null) { 
      list = new ArrayList<String>(1); 
      list.add(header.getValue()); 
      result.put(header.getName(), list); 
     } 
     else list.add(header.getValue()); 

    } 
    return result; 
} 

La prossima cosa che vi serve è modificare DiskBasedCache.writeStringStringMap e DiskBasedCache.readStringStringMap metodi. Dovrebbero supportare più valori. Qui vengono modificati i metodi con i metodi helper:

static void writeStringStringMap(Map<String, List<String>> map, OutputStream os) throws IOException { 
    if (map != null) { 
     writeInt(os, map.size()); 
     for (Map.Entry<String, List<String>> entry : map.entrySet()) { 
      writeString(os, entry.getKey()); 
      writeString(os, joinStringsList(entry.getValue())); 
     } 
    } else { 
     writeInt(os, 0); 
    } 
} 

static Map<String, List<String>> readStringStringMap(InputStream is) throws IOException { 
    int size = readInt(is); 
    Map<String, List<String>> result = (size == 0) 
      ? Collections.<String, List<String>>emptyMap() 
      : new HashMap<String, List<String>>(size); 
    for (int i = 0; i < size; i++) { 
     String key = readString(is).intern(); 
     String value = readString(is).intern(); 
     result.put(key, parseNullStringsList(value)); 
    } 
    return result; 
} 

static List<String> parseNullStringsList(String str) { 
    String[] strs = str.split("\0"); 
    return Arrays.asList(strs); 
} 

static String joinStringsList(List<String> list) { 
    StringBuilder ret = new StringBuilder(); 
    boolean first = true; 
    for (String str : list) { 
     if (first) first = false; 
     else ret.append("\0"); 
     ret.append(str); 
    } 
    return ret.toString(); 
} 

e l'ultima cosa è HttpHeaderParser classe. Si dovrebbe rendere il suo metodo parseCacheHeaders supporto per più valori. Utilizzare il seguente metodo di supporto per questo:

public static String getHeaderValue(List<String> list) { 
    if ((list == null) || list.isEmpty()) return null; 
    return list.get(0); 
} 

E l'ultima cosa da modificare è un mucchio di posti per sostituire

Map<String, String> 

a

Map<String, List<String>> 

Usa il tuo IDE per fare questo.

+0

Ciao @ ruslan-yanchyshyn, potresti inserire il codice completo per vedere l'esempio? Sto cercando di seguire i tuoi passi, ma quando provo a scavalcare BasicNetwork ho molte dipendenze. Potresti aiutarmi? –

0

Domanda piuttosto vecchia, ma se aiuta qualcuno.Nella nuovissima scarica hai:

protected Response<String> parseNetworkResponse(NetworkResponse response) 
{ 
    List<Header> headers = response.allHeaders; 

    String sessionId = null; 

    for (Header header : headers) 
    { 
     // header.getName(); 
     // header.getValue(); 
    } 

    return super.parseNetworkResponse(response); 
}