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?

有帮助吗?

解决方案

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top