Android Volley, duplicate Set-Cookie is overridden

匿名 (未验证) 提交于 2019-12-03 02:45:02

问题:

Trying to use Volley lib as a network wrapper for my android application. I have a connection up and running, but the problem is that every time there is multiple "Set-Cookie" headers in the response Volley uses Map that cannot have duplicate keys, and will only store the last Set-cookie header and overwrite the rest.

Is there a workaround for this issue?

Is there another lib to use?

回答1:

I tried overiding classes to fix this but when I had to edit NetworkResponse, I was descending too far down the rabbithole. So I decided to just edit Volley directly to grab all response headers in an array and not a Map.

My fork is on GitHub and I included an example usage activity.

I made changes to NetworkResponse.java, BasicNetwork.java and HurlStack.java as detailed in this commit.

Then to use in your actual apps you do something like this

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

It's a dirty little hack but seems to work well for me at the moment.



回答2:

The first thing you need is to modify BasicNetwork.convertHeaders method to make it support multiple map values. Here is example of modified method:

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

Next thing you need is to modify DiskBasedCache.writeStringStringMap and DiskBasedCache.readStringStringMap methods. They should support multiple values. Here are modified methods along with helper methods:

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

And last thing is HttpHeaderParser class. You should make its parseCacheHeaders method support multiple values. Use the following helper method for this:

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

And the latest thing to modify is a bunch of places to replace

Map<String, String> 

to

Map<String, List<String>> 

Use your IDE to do this.



回答3:

You can override Network class of volley. Looking at performRequest and convertHeaders methods of BasicNetwork might help. Then, passing your Network implementation to the contructor of RequestQueue like:

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



回答4:

Question pretty old, but if helps someone. In newest volley you have:

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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!