19

尝试使用 Volley lib 作为我的 android 应用程序的网络包装器。我已经建立并运行了一个连接,但问题是每次响应中有多个“Set-Cookie”标头时 Volley 使用不能有重复键的 Map,并且只会存储最后一个 Set-cookie 标头并覆盖其余标头.

这个问题有解决方法吗?

是否有另一个库可以使用?

4

4 回答 4

17

我尝试覆盖类来解决这个问题,但是当我不得不编辑NetworkResponse时,我在兔子洞中下降得太远了。所以我决定直接编辑 Volley 来获取数组中的所有响应头,而不是 Map。

我的 fork 在GitHub 上,我包含了一个示例使用活动

我对 NetworkResponse.java、BasicNetwork.java 和 HurlStack.java 进行了更改,如本次提交中所述。

然后在你的实际应用中使用你做这样的事情

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

这是一个肮脏的小技巧,但目前看来对我来说效果很好。

于 2013-10-30T03:56:24.063 回答
3

您需要做的第一件事是修改BasicNetwork.convertHeaders方法以使其支持多个地图值。以下是修改方法的示例:

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

接下来您需要修改DiskBasedCache.writeStringStringMapDiskBasedCache.readStringStringMap方法。它们应该支持多个值。以下是修改后的方法以及辅助方法:

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

最后一件事是HttpHeaderParser类。您应该使其parseCacheHeaders方法支持多个值。为此,请使用以下辅助方法:

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

而且最近要修改的是一堆要替换的地方

Map<String, String>

Map<String, List<String>>

使用您的 IDE 来执行此操作。

于 2015-03-11T10:33:58.677 回答
3

问题很老了,但如果对某人有帮助。在最新的凌空抽射中,您拥有:

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);
}
于 2018-02-14T21:30:50.277 回答
1

您可以覆盖凌空的网络类。查看BasicNetwork的 performRequest 和 convertHeaders 方法可能会有所帮助。然后,将您的网络实现传递给 RequestQueue 的构造函数,例如:

新的请求队列(新的 NoCache(),新的 YourOwnNetwork());

于 2013-10-07T10:18:18.500 回答