Android Volley, дубликат Set-Cookie отменен

Попытка использовать Volley lib в качестве сетевой оболочки для моего приложения для Android. У меня есть соединение и работает, но проблема в том, что каждый раз, когда в ответе есть несколько заголовков "Set-Cookie", Volley использует Map, у которых нет дубликатов ключей, и будет хранить только последний заголовок Set-cookie и перезаписать остальные.

Есть ли обходной путь для этой проблемы?

Есть ли другой lib для использования?

Ответ 1

Я попытался переопределить классы, чтобы исправить это, но когда мне пришлось редактировать NetworkResponse, я спускался слишком далеко вниз по раввиту. Поэтому я решил просто отредактировать Volley непосредственно, чтобы захватить все заголовки ответов в массиве, а не в Map.

Мой форк находится на 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);
        }

Это грязный маленький взлом, но, похоже, для меня сейчас хорошо работает.

Ответ 2

Прежде всего вам нужно изменить метод 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.writeStringStringMap и DiskBasedCache.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.

Ответ 3

Вы можете переопределить Network класс залпа. Рассмотрение методов executeRequest и convertHeaders BasicNetwork может помочь. Затем, передав реализацию вашей сети в contructor RequestQueue, например:

новый RequestQueue (новый NoCache(), новый YourOwnNetwork());