2013-09-25 77 views
19

Cố gắng sử dụng Volley lib làm trình bao bọc mạng cho ứng dụng Android của tôi. Tôi có một kết nối và chạy, nhưng vấn đề là mỗi khi có nhiều tiêu đề "Set-Cookie" trong phản hồi Volley sử dụng Bản đồ không thể có các khóa trùng lặp và sẽ chỉ lưu trữ tiêu đề Set-cookie cuối cùng và ghi đè phần còn lại .Android Volley, Duplicate Set-Cookie bị ghi đè

Có giải pháp cho vấn đề này không?

Có lib khác để sử dụng không?

+2

Chỉ cần chú ý đến điều này, điều này thật lố bịch từ Google. Rõ ràng thư viện này là dành cho những thứ rất nhẹ. – georgiecasey

+0

Đó không phải là vấn đề với Android Volley. Đó là một vấn đề của các máy chủ web. Set-Cookie không được nhiều. http://stackoverflow.com/questions/11533867/set-cookie-header-with-multiple-cookies –

+0

http://stackoverflow.com/a/25388897/2819864 là giải pháp nhanh nhất – RominaV

Trả lời

16

Tôi đã cố gắng thực hiện các lớp học để sửa lỗi này nhưng khi tôi phải chỉnh sửa NetworkResponse, tôi đã giảm dần quá xa rabbithole. Vì vậy, tôi quyết định chỉ chỉnh sửa Volley trực tiếp để lấy tất cả các tiêu đề phản hồi trong một mảng chứ không phải Bản đồ.

Ngã ba của tôi ở số GitHub và tôi đã bao gồm example usage activity.

Tôi đã thực hiện các thay đổi đối với NetworkResponse.java, BasicNetwork.java và HurlStack.java như được nêu chi tiết trong this commit.

Sau đó, để sử dụng trong các ứng dụng thực tế của bạn, bạn làm điều gì đó như thế này

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

Đó là một chút bẩn hack nhưng dường như làm việc tốt cho tôi vào lúc này.

+1

Tôi ngạc nhiên vì điều này chưa có trong bản phát hành chính thức. Bạn có biết tại sao? –

1

Bạn có thể ghi đè Network lớp bóng chuyền. Nhìn vào các phương thức performRequest và convertHeaders của BasicNetwork có thể hữu ích. Sau đó, chuyển giao triển khai Mạng của bạn đến contructor của RequestQueue như:

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

+0

Xin chào @Kazuki, bạn có thể đặt và ví dụ? Tôi đã tạo giao diện riêng của Mạng (CustomNetwork) với perfomRequest. Sau đó, tôi sửa đổi việc thực hiện nó nhưng tôi không thể vượt qua CustomNetwork trong RequestQueue mới (...). Bạn có thể giúp tôi? –

3

Điều đầu tiên bạn cần là sửa đổi phương thức BasicNetwork.convertHeaders để làm cho nó hỗ trợ nhiều giá trị bản đồ. Dưới đây là ví dụ về phương pháp chỉnh sửa:

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

Sau đó bạn cần là để sửa đổi DiskBasedCache.writeStringStringMapDiskBasedCache.readStringStringMap phương pháp. Họ nên hỗ trợ nhiều giá trị. Dưới đây là sửa đổi phương pháp đó cùng với các phương pháp helper:

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

Và điều cuối cùng là HttpHeaderParser lớp. Bạn nên thực hiện phương thức parseCacheHeaders hỗ trợ nhiều giá trị. Sử dụng các phương pháp sau đây helper cho việc này:

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

Và điều mới nhất để thay đổi là một loạt các nơi để thay thế

Map<String, String> 

để

Map<String, List<String>> 

sử dụng IDE của bạn để làm điều này.

+0

Hi @ ruslan-yanchyshyn, bạn có thể đặt mã đầy đủ để xem ví dụ không? Tôi đang cố gắng làm theo các bước của bạn, nhưng khi tôi cố gắng ghi đè BasicNetwork, tôi có rất nhiều phụ thuộc. Bạn có thể giúp tôi? –

0

Câu hỏi khá cũ, nhưng nếu giúp ai đó.Trong cú volley mới nhất, bạn có:

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