Android Volley, duplicate Set-Cookie is overridden

谁说我不能喝 提交于 2019-11-30 00:13:59

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.

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.

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

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

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