2013-09-25 15 views
19

Próbujesz użyć Volley lib jako opakowania sieciowego dla mojej aplikacji na Androida. Mam połączenie uruchomione, ale problem polega na tym, że za każdym razem, gdy w odpowiedzi znajduje się wiele nagłówków "Set-Cookie", Volley używa Map, która nie może mieć duplikatów kluczy, i przechowuje tylko ostatni nagłówek Set-cookie i nadpisuje resztę .Android Volley, duplikat Set-Cookie jest nadpisywany

Czy istnieje obejście tego problemu?

Czy jest dostępna inna biblioteka?

+2

Zauważ to sam, to niedorzeczne z Google. To oczywiste, że ta biblioteka jest przeznaczona do bardzo lekkich rzeczy. – georgiecasey

+0

To nie jest problem z systemem Android Volley. Jest to problem serwerów sieciowych. Set-Cookie nie może być wielokrotnością. http://stackoverflow.com/questions/11533867/set-cookie-header-with-multiple-cookies –

+0

http://stackoverflow.com/a/25388897/2819864 jest najszybszym rozwiązaniem – RominaV

Odpowiedz

16

Próbowałem przerobić klasy, aby to naprawić, ale kiedy musiałem edytować NetworkResponse, schodziłem zbyt daleko w dół rabbithole. Postanowiłem więc po prostu edytować Volley bezpośrednio, aby pobrać wszystkie nagłówki odpowiedzi w tablicy, a nie Mapę.

Mój widelec jest na GitHub i dołączyłem example usage activity.

Wprowadziłem zmiany w NetworkResponse.java, BasicNetwork.java i HurlStack.java zgodnie z this commit.

Następnie do wykorzystania w rzeczywistych aplikacjach można zrobić coś jak ten

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); 
     } 

To jest trochę brudny siekać ale wydaje się działać dobrze dla mnie w tej chwili.

+1

Jestem zaskoczony, że nie ma jeszcze oficjalnego wydania. Wiesz dlaczego? –

1

Możesz zastąpić klasę salwy Network. Przyglądanie się metodom performRequest i convertHeaders z poziomu BasicNetwork może pomóc. Następnie przekazując implementację sieci do kontrahenta RequestQueue, takiego jak:

new RequestQueue (nowy NoCache(), nowy YourOwnNetwork());

+0

Witam @Kazuki, czy możesz umieścić i przykład? Stworzyłem własny interfejs sieci (CustomNetwork) z perfomRequest. Następnie modyfikuję jego implementację, ale nie mogę przekazać niestandardowej sieci w nowej kwerendzie RequestQueue (...). Czy mógłbyś mi pomóc? –

3

Najpierw należy zmodyfikować metodę BasicNetwork.convertHeaders, aby umożliwić obsługę wielu wartości map. Oto przykład metody zmodyfikowanej:

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; 
} 

Następna rzecz to trzeba zmodyfikować DiskBasedCache.writeStringStringMap i DiskBasedCache.readStringStringMap metod. Powinny obsługiwać wiele wartości. Tutaj są zmodyfikowane metody wraz z metod pomocniczych:

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(); 
} 

I ostatnia rzecz jest HttpHeaderParser klasa. Powinieneś uczynić jego metodę parseCacheHeaders wspierającą wiele wartości. Użyj następującej metody pomocnika dla tego:

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

a najnowsze rzeczy do zmiany jest kilka miejsc do zastąpienia

Map<String, String> 

do

Map<String, List<String>> 

Użyj IDE to zrobić.

+0

Witam @ ruslan-yanchyshyn, czy możesz umieścić pełny kod, aby zobaczyć przykład? Próbuję wykonać twoje kroki, ale kiedy próbuję zastąpić BasicNetwork, mam wiele zależności. Czy mógłbyś mi pomóc? –

0

Pytanie dość stare, ale jeśli komuś pomaga.W najnowszej siatkówce masz:

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); 
} 
Powiązane problemy