网络请求框架——OkGo解读(二)——cookie
来源:互联网 发布:raysource是什么软件 编辑:程序博客网 时间:2024/06/06 01:32
cookie:
public interface CookieStore { /** 保存url对应所有cookie */ void saveCookies(HttpUrl url, List<Cookie> cookie); /** 加载url所有的cookie */ List<Cookie> loadCookies(HttpUrl url); /** 获取当前所有保存的cookie */ List<Cookie> getAllCookie(); /** 根据url和cookie移除对应的cookie */ boolean removeCookie(HttpUrl url, Cookie cookie); /** 根据url移除所有的cookie */ boolean removeCookies(HttpUrl url); /** 移除所有的cookie */ boolean removeAllCookie();}
public class PersistentCookieStore implements CookieStore { private static final String LOG_TAG = "PersistentCookieStore"; private static final String COOKIE_PREFS = "okgo_cookie"; //cookie使用prefs保存 private static final String COOKIE_NAME_PREFIX = "cookie_"; //cookie持久化的统一前缀 private final HashMap<String, ConcurrentHashMap<String, Cookie>> cookies; private final SharedPreferences cookiePrefs; public PersistentCookieStore() { cookiePrefs = OkGo.getContext().getSharedPreferences(COOKIE_PREFS, Context.MODE_PRIVATE); cookies = new HashMap<>(); //将持久化的cookies缓存到内存中,数据结构为 Map<Url.host, Map<Cookie.name, Cookie>> Map<String, ?> prefsMap = cookiePrefs.getAll(); for (Map.Entry<String, ?> entry : prefsMap.entrySet()) { if ((entry.getValue()) != null && !entry.getKey().startsWith(COOKIE_NAME_PREFIX)) { //获取url对应的所有cookie的key,用","分割 String[] cookieNames = TextUtils.split((String) entry.getValue(), ","); for (String name : cookieNames) { //根据对应cookie的Key,从xml中获取cookie的真实值 String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null); if (encodedCookie != null) { Cookie decodedCookie = decodeCookie(encodedCookie); if (decodedCookie != null) { if (!cookies.containsKey(entry.getKey())) cookies.put(entry.getKey(), new ConcurrentHashMap<String, Cookie>()); cookies.get(entry.getKey()).put(name, decodedCookie); } } } } } } private String getCookieToken(Cookie cookie) { return cookie.name() + "@" + cookie.domain(); } /** 当前cookie是否过期 */ private static boolean isCookieExpired(Cookie cookie) { return cookie.expiresAt() < System.currentTimeMillis(); } /** 根据当前url获取所有需要的cookie,只返回没有过期的cookie */ @Override public List<Cookie> loadCookies(HttpUrl url) { ArrayList<Cookie> ret = new ArrayList<>(); if (cookies.containsKey(url.host())) { Collection<Cookie> urlCookies = cookies.get(url.host()).values(); for (Cookie cookie : urlCookies) { if (isCookieExpired(cookie)) { removeCookie(url, cookie); } else { ret.add(cookie); } } } return ret; } /** 将url的所有Cookie保存在本地 */ @Override public void saveCookies(HttpUrl url, List<Cookie> urlCookies) { if (!cookies.containsKey(url.host())) { cookies.put(url.host(), new ConcurrentHashMap<String, Cookie>()); } for (Cookie cookie : urlCookies) { //当前cookie是否过期 if (isCookieExpired(cookie)) { removeCookie(url, cookie); } else { saveCookie(url, cookie, getCookieToken(cookie)); } } } /** * 保存cookie,并将cookies持久化到本地,数据结构为 * Url.host -> Cookie1.name,Cookie2.name,Cookie3.name * cookie_Cookie1.name -> CookieString * cookie_Cookie2.name -> CookieString */ private void saveCookie(HttpUrl url, Cookie cookie, String name) { //内存缓存 cookies.get(url.host()).put(name, cookie); //文件缓存 SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet())); prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie(new SerializableHttpCookie(cookie))); prefsWriter.commit(); } /** 根据url移除当前的cookie */ @Override public boolean removeCookie(HttpUrl url, Cookie cookie) { String name = getCookieToken(cookie); if (cookies.containsKey(url.host()) && cookies.get(url.host()).containsKey(name)) { //内存移除 cookies.get(url.host()).remove(name); //文件移除 SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); if (cookiePrefs.contains(COOKIE_NAME_PREFIX + name)) { prefsWriter.remove(COOKIE_NAME_PREFIX + name); } prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet())); prefsWriter.commit(); return true; } else { return false; } } @Override public boolean removeCookies(HttpUrl url) { if (cookies.containsKey(url.host())) { //文件移除 Set<String> cookieNames = cookies.get(url.host()).keySet(); SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); for (String cookieName : cookieNames) { if (cookiePrefs.contains(COOKIE_NAME_PREFIX + cookieName)) { prefsWriter.remove(COOKIE_NAME_PREFIX + cookieName); } } prefsWriter.remove(url.host()); prefsWriter.commit(); //内存移除 cookies.remove(url.host()); return true; } else { return false; } } @Override public boolean removeAllCookie() { SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); prefsWriter.clear(); prefsWriter.commit(); cookies.clear(); return true; } /** 获取所有的cookie */ @Override public List<Cookie> getAllCookie() { ArrayList<Cookie> ret = new ArrayList<>(); for (String key : cookies.keySet()) ret.addAll(cookies.get(key).values()); return ret; } /** * cookies 序列化成 string * * @param cookie 要序列化的cookie * @return 序列化之后的string */ protected String encodeCookie(SerializableHttpCookie cookie) { if (cookie == null) return null; ByteArrayOutputStream os = new ByteArrayOutputStream(); try { ObjectOutputStream outputStream = new ObjectOutputStream(os); outputStream.writeObject(cookie); } catch (IOException e) { Log.d(LOG_TAG, "IOException in encodeCookie", e); return null; } return byteArrayToHexString(os.toByteArray()); } /** * 将字符串反序列化成cookies * * @param cookieString cookies string * @return cookie object */ protected Cookie decodeCookie(String cookieString) { byte[] bytes = hexStringToByteArray(cookieString); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); Cookie cookie = null; try { ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); cookie = ((SerializableHttpCookie) objectInputStream.readObject()).getCookie(); } catch (IOException e) { Log.d(LOG_TAG, "IOException in decodeCookie", e); } catch (ClassNotFoundException e) { Log.d(LOG_TAG, "ClassNotFoundException in decodeCookie", e); } return cookie; } /** * 二进制数组转十六进制字符串 * * @param bytes byte array to be converted * @return string containing hex values */ protected String byteArrayToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); for (byte element : bytes) { int v = element & 0xff; if (v < 16) { sb.append('0'); } sb.append(Integer.toHexString(v)); } return sb.toString().toUpperCase(Locale.US); } /** * 十六进制字符串转二进制数组 * * @param hexString string of hex-encoded values * @return decoded byte array */ protected byte[] hexStringToByteArray(String hexString) { int len = hexString.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16)); } return data; }}
cookie的内存管理:
public class MemoryCookieStore implements CookieStore { private final HashMap<String, List<Cookie>> memoryCookies = new HashMap<>(); @Override public synchronized void saveCookies(HttpUrl url, List<Cookie> cookies) { List<Cookie> oldCookies = memoryCookies.get(url.host()); List<Cookie> needRemove = new ArrayList<>(); for (Cookie newCookie : cookies) { for (Cookie oldCookie : oldCookies) { if (newCookie.name().equals(oldCookie.name())) { needRemove.add(oldCookie); } } } oldCookies.removeAll(needRemove); oldCookies.addAll(cookies); } @Override public synchronized List<Cookie> loadCookies(HttpUrl url) { List<Cookie> cookies = memoryCookies.get(url.host()); if (cookies == null) { cookies = new ArrayList<>(); memoryCookies.put(url.host(), cookies); } return cookies; } @Override public synchronized List<Cookie> getAllCookie() { List<Cookie> cookies = new ArrayList<>(); Set<String> httpUrls = memoryCookies.keySet(); for (String url : httpUrls) { cookies.addAll(memoryCookies.get(url)); } return cookies; } @Override public synchronized boolean removeCookie(HttpUrl url, Cookie cookie) { List<Cookie> cookies = memoryCookies.get(url.host()); return (cookie != null) && cookies.remove(cookie); } @Override public synchronized boolean removeCookies(HttpUrl url) { return memoryCookies.remove(url.host()) != null; } @Override public synchronized boolean removeAllCookie() { memoryCookies.clear(); return true; }}扩展了解 以下内容:
/* HttpUrl 类
统一资源定位符 http 或 https 使用这个类进行组合和分解 互联网地址
还可用做URL的解析 (点击相关链接指定页面)
用于检索资源,尽管url有多种,这个类只支持http、https
*/
expiresAt 到期时间
domain true时为唯一的域
path cookie的路径
secure 为true时是仅限于https(安全)
httpOnly 为true时 仅限于http 在web浏览器可防止cookie访问脚本
persistent 回话是否到期 失效 内容能够被保存的时间
private Cookie(String name, String value, long expiresAt, String domain, String path, boolean secure, boolean httpOnly, boolean hostOnly, boolean persistent) { this.name = name; this.value = value; this.expiresAt = expiresAt; this.domain = domain; this.path = path; this.secure = secure; this.httpOnly = httpOnly; this.hostOnly = hostOnly; this.persistent = persistent;}
cookie 的序列化:
public class SerializableHttpCookie implements Serializable { private static final long serialVersionUID = 6374381323722046732L; private transient final Cookie cookie; private transient Cookie clientCookie; public SerializableHttpCookie(Cookie cookie) { this.cookie = cookie; } public Cookie getCookie() { Cookie bestCookie = cookie; if (clientCookie != null) { bestCookie = clientCookie; } return bestCookie; } private void writeObject(ObjectOutputStream out) throws IOException { out.writeObject(cookie.name()); out.writeObject(cookie.value()); out.writeLong(cookie.expiresAt()); out.writeObject(cookie.domain()); out.writeObject(cookie.path()); out.writeBoolean(cookie.secure()); out.writeBoolean(cookie.httpOnly()); out.writeBoolean(cookie.hostOnly()); out.writeBoolean(cookie.persistent()); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { String name = (String) in.readObject(); String value = (String) in.readObject(); long expiresAt = in.readLong(); String domain = (String) in.readObject(); String path = (String) in.readObject(); boolean secure = in.readBoolean(); boolean httpOnly = in.readBoolean(); boolean hostOnly = in.readBoolean(); boolean persistent = in.readBoolean(); Cookie.Builder builder = new Cookie.Builder(); builder = builder.name(name); builder = builder.value(value); builder = builder.expiresAt(expiresAt); builder = hostOnly ? builder.hostOnlyDomain(domain) : builder.domain(domain); builder = builder.path(path); builder = secure ? builder.secure() : builder; builder = httpOnly ? builder.httpOnly() : builder; clientCookie = builder.build(); }}
CookieJar的实现类
public class CookieJarImpl implements CookieJar { private CookieStore cookieStore; private Map<String, Set<Cookie>> userCookies = new HashMap<>(); //用户手动添加的Cookie public void addCookies(List<Cookie> cookies) { for (Cookie cookie : cookies) { String domain = cookie.domain(); Set<Cookie> domainCookies = userCookies.get(domain); if (domainCookies == null) { domainCookies = new HashSet<>(); userCookies.put(domain, domainCookies); } domainCookies.add(cookie); } } public CookieJarImpl(CookieStore cookieStore) { if (cookieStore == null) { throw new IllegalArgumentException("cookieStore can not be null!"); } this.cookieStore = cookieStore; } @Override public synchronized void saveFromResponse(HttpUrl url, List<Cookie> cookies) { cookieStore.saveCookies(url, cookies); //这里调用接口的保存cookies方法 } // 分别把cookie保存到了 内存 和 sp @Override public synchronized List<Cookie> loadForRequest(HttpUrl url) { List<Cookie> requestUrlCookies = cookieStore.loadCookies(url); Set<Cookie> userUrlCookies = userCookies.get(url.host()); Set<Cookie> cookieSet = new HashSet<>(); if (requestUrlCookies != null) cookieSet.addAll(requestUrlCookies); if (userUrlCookies != null) cookieSet.addAll(userUrlCookies); return new ArrayList<>(cookieSet); } public CookieStore getCookieStore() { return cookieStore; }}
扩展了解: CookieJar 实现这个接口 负责选择 cookie的接受和拒绝
public interface CookieJar { /** A cookie jar that never accepts any cookies. */ CookieJar NO_COOKIES = new CookieJar() { @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) { } @Override public List<Cookie> loadForRequest(HttpUrl url) { return Collections.emptyList(); } }; /** * Saves {@code cookies} from an HTTP response to this store according to this jar's policy. * * <p>Note that this method may be called a second time for a single HTTP response if the response * includes a trailer. For this obscure HTTP feature, {@code cookies} contains only the trailer's * cookies. */ void saveFromResponse(HttpUrl url, List<Cookie> cookies); /** * Load cookies from the jar for an HTTP request to {@code url}. This method returns a possibly * empty list of cookies for the network request. * * <p>Simple implementations will return the accepted cookies that have not yet expired and that * {@linkplain Cookie#matches match} {@code url}. */ List<Cookie> loadForRequest(HttpUrl url);}
0 0
- 网络请求框架——OkGo解读(二)——cookie
- 网络请求框架——OkGo解读(一)——数据的缓存
- 网络请求框架——OkGo解读(三)——request
- okhttp-OkGo(okhttp-util升级版)网络请求框架(二)
- Android框架之路——OkGo的使用
- 网络请求框架OkHttp改名的OkGo的介绍(以防丢失)
- okhttp-OkGo(okhttp-util升级版)网络请求框架(一)
- OKRx+OkGo(okhttp-util升级版)网络请求框架使用
- NoHttp使用简析——Android网络请求框架(二)
- Volley网络请求框架简析——Android网络请求框架(三)
- Retrofit网络请求框架使用简析——Android网络请求框架(四)
- 利用ASIHttpRequest框架进行网络数据请求(二)—— 利用post发送表单请求数据
- Android —— 网络请求框架 Volley
- android网络开源框架volley(二)——自定义你的请求对象
- OkGO一个专注于让网络请求更简单的框架
- Android网络篇—Retrofit网络请求框架详解
- HBuilder开发APP(二)——网络请求
- android okGo、okHttp、XUtils网络框架使用
- 人眼的关注度不同,在视频压缩和图像处理领域,有完全相反的准则
- nod32更新服务无法设置问题更改
- reactjs性能优化之shouldComponentUpdate
- Spring Boot Maven 管理 pom.xml
- 查询文章中单词出现的个数和所在的行数。
- 网络请求框架——OkGo解读(二)——cookie
- React.js生态系统概览 [译]
- Android 小项目之--Mini音乐播放器【简单版】(附源码)
- 图解Git
- Android绘图初步—Path
- java.lang.UnsupportedOperationException: Can't convert to dimension: type=0x10
- Android小項目之---時間線程應用(附源碼)
- 网游创业为什么会失败?
- 字符串包含问题