教你认清HttpURLConnection里面的CookieManager,CookieStore,CookieHandler,HttpCookie,CookiePolicy
来源:互联网 发布:godaddy域名被转走 编辑:程序博客网 时间:2024/06/05 23:41
一.结构大纲。
关于HttpURLConnection的一些用法,相信大家都很熟练了,如果你不想用网上一些网络框架,不凡可以自己封装下HttpURLConnection,自己封装自己用感觉还是不错的。好了回到正题,大家访问服务器的话,要想保持连接,必然要涉及到Cookie的保存,而在网络请求中,谷歌爸爸早已封装了一些类来帮助我们进行Cookie的保存。现在我们来认识一下CookieManager,CookieStore,CookieHandler,HttpCookie,CookiePolicy 他们之间的区别,先看一张Visio图,
二.结构解析。
可以看到CookieHandler是一个抽象类,里面封装了用于保存Cookie获取Cookie的一系列抽象方法;而CookieManager则是CookieHandler的实现类,继承了CookieHandler,也就是CookieManager里面实现了保存Cookie获取Cookie的一系列方法,至于怎么实现,我们等下再来看源码,继续看他们的结构。CookieManager的构造方法出现了两个类分别是CookieStore 和 CookiePolicy,那么这两个类又是什么呢?可以看到CookieStore是用来存储Cookie的。这里要注意下区别,CookieManager是实现了保存Cookie获取Cookie的方法,而CookieStore是用来存储Cookie的,实际上,CookieManager保存Cookie就是通过CookieStore来保存的,它里面有CookieStore,后面源码会介绍到。继续看,知道了CookieStore是用来存储Cookie,但是它里面怎么有个HttpCookie的类?我们可以大胆猜测这个一个封装Cookie的类,确实是这样,HttpCookie根据请求的响应头,从set-cookie请求头中取出Cookie,然后拆分出name,path,domain(域名),value,集合成一起的一个类。而至于CookiePolicy,他代表的是一种Cookie保存政策,里面提供三种字段,来确定当前Cookie是否应该接受还是拒绝。可以看到CookieManager是一个采取一定的Cookie保存政策的一个Cookie管理者(没有设置CookiePolicy的话会有默认值),内部是通过CookieStore来存储Cookie。
三.源码解析。
首先先来看CookieManager
我们来看下它的源码结构:
public class CookieManager extends CookieHandler { private CookieStore store; private CookiePolicy policy; private static final String VERSION_ZERO_HEADER = "Set-cookie"; private static final String VERSION_ONE_HEADER = "Set-cookie2"; ....}首先从成员变量上看,CookieManager内部带有两个成员变量CookieStore,CookiePolicy,而下面两个常量Set-Cookie,想必就不用说了吧,很明显是Cookie的返回请求头,Set-cookie是cookie版本version为0的请求头,而Set-cookie2是cookie版本version为1的请求头,可以自行谷歌。
我们来看他的关键代码,也就是那个put(URI uri , Map<String , List<String>> responseHeaders)
@Override public void put(URI uri, Map<String, List<String>> responseHeaders) throws IOException { ...//省略无关的代码 // parse and construct cookies according to the map List<HttpCookie> cookies = parseCookie(responseHeaders); for (HttpCookie cookie : cookies) { // if the cookie doesn't have a domain, set one. The policy will do validation. if (cookie.getDomain() == null) { cookie.setDomain(uri.getHost()); } // if the cookie doesn't have a path, set one. If it does, validate it. if (cookie.getPath() == null) { cookie.setPath(pathToCookiePath(uri.getPath())); } else if (!HttpCookie.pathMatches(cookie, uri)) { continue; } // if the cookie has the placeholder port list "", set the port. Otherwise validate it. if ("".equals(cookie.getPortlist())) { cookie.setPortlist(Integer.toString(uri.getEffectivePort())); } else if (cookie.getPortlist() != null && !HttpCookie.portMatches(cookie, uri)) { continue; } // if the cookie conforms to the policy, add it into the store if (policy.shouldAccept(uri, cookie)) { store.add(uri, cookie); } } }
这里调用到了parseCookie(responseHeaders)这个方法,至于Map<String ,List<String>> responseHeader , 这个参数,大家看着看着是不是感觉很熟悉,没错就是 httpUrlConnection.getHeaderFields() 的返回值,该方法是返回响应头的所有头字段和值,当然我们只要Cookie的话只需要找到Set-cookie/Set-cookie2字段,我们看下这个parseCookie方法
private static List<HttpCookie> parseCookie(Map<String, List<String>> responseHeaders) { List<HttpCookie> cookies = new ArrayList<HttpCookie>(); for (Map.Entry<String, List<String>> entry : responseHeaders.entrySet()) { String key = entry.getKey(); // Only "Set-cookie" and "Set-cookie2" pair will be parsed if (key != null && (key.equalsIgnoreCase(VERSION_ZERO_HEADER) || key.equalsIgnoreCase(VERSION_ONE_HEADER))) { // parse list elements one by one for (String cookieStr : entry.getValue()) { try { for (HttpCookie cookie : HttpCookie.parse(cookieStr)) { cookies.add(cookie); } } catch (IllegalArgumentException ignored) { // this string is invalid, jump to the next one. } } } } return cookies; }果然没错,是 根据VERSION_ZERO_HEADER(Set-cookie)来判断的,那么既然他是根据Set-cookie来找出Cookie的,它是怎么解析出来的呢?来,我们看下他这个
for (HttpCookie cookie : HttpCookie.parse(cookieStr)) { cookies.add(cookie); }点进去
public static List<HttpCookie> parse(String header) { return new CookieParser(header).parse(); }再点击那个parse进去看,可以看到
public List<HttpCookie> parse() { List<HttpCookie> cookies = new ArrayList<HttpCookie>(2); // The RI permits input without either the "Set-Cookie:" or "Set-Cookie2" headers. boolean pre2965 = true; if (inputLowerCase.startsWith("set-cookie2:")) { pos += "set-cookie2:".length(); pre2965 = false; hasVersion = true; } else if (inputLowerCase.startsWith("set-cookie:")) { pos += "set-cookie:".length(); } ...//省略无关代码 String value = readAttributeValue(pre2965 ? ";" : ",;"); HttpCookie cookie = new HttpCookie(name, value); cookie.version = pre2965 ? 0 : 1; cookies.add(cookie);}可以看到,跟我们猜想的一样,HttpCookie.parse(cookieStr)中是根据Set-cookie字段来拆分Cookie的,拆分出name,value,path,domain等然后合并成一个List<HttpCookie>集合,每一个HttpCookie就代表了一个Cookie信息。
好,回到刚刚CookieManager的put方法上,put方法里面调用了
List<HttpCookie> cookies = parseCookie(responseHeaders);这个方法解析出响应头字段中的cookie信息,但是怎么还没保存呢?别急,继续看下去,可以看到CookieStore终于出场了
// if the cookie conforms to the policy, add it into the store if (policy.shouldAccept(uri, cookie)) { store.add(uri, cookie); }它先根据CookiePolicy的规则判断当前cookie是否要接受保存,如果是则添加到CookieStore里。到这里相比大家都有点豁然开朗的感觉吧。没错,CookieManager内部是采用CookiePolicy来定制cookie保存规则,而真正保存是使用CookieStore来保存的,至于怎么保存,大家可以自行阅读源码啦。相信大家对CookieHandler,CookieManger,CookieStore,CookiePolicy,HttpCookie已经有了大概的了解了吧,既然知道原理,那还等什么,赶紧实践下
四.Cookie实践。
eg:
CookieManager cookieManager = new CookieManager();//这个方法就可以把Cookie保存在CookieStore里面了cookieManager.put(new URI(url) , httpURLConnection.getHeaderFields());//获取CookieStoreCookieStore cookieStore = cookieManager.getCookieStore();//再拿出里面的HttpCookie for (HttpCookie httpCookie : cookieStore.getCookies()) { Log.e(TAG, "httpCookie: domain " + httpCookie.getDomain()); Log.e(TAG, "httpCookie: value " + httpCookie.getValue()); Log.e(TAG, "httpCookie: path " + httpCookie.getPath()); Log.e(TAG, "httpCookie: name " + httpCookie.getName()); Log.e(TAG, "httpCookie: toString " + httpCookie.toString()); }
我们来看下打印数据
09-24 15:14:06.573 /com.rdc.zzh.networkutil E/NetworkUtil: httpCookie: domain .baidu.com09-24 15:14:06.573 /com.rdc.zzh.networkutil E/NetworkUtil: httpCookie: value 172DB173E657AEA43F99877C03311B50:FG=109-24 15:14:06.573 /com.rdc.zzh.networkutil E/NetworkUtil: httpCookie: path /09-24 15:14:06.573 /com.rdc.zzh.networkutil E/NetworkUtil: httpCookie: name BAIDUID09-24 15:14:06.573 /com.rdc.zzh.networkutil E/NetworkUtil: httpCookie: toString BAIDUID=172DB173E657AEA43F99877C03311B50:FG=1
好了,我们来总结下:
五.总结。
①CookieHandler是抽象类,而CookieManager是CookieHandler的实现类,内存采用CookiePolicy来定制cookie保存规则,而真正保存是使用CookieStore来保存的
②HttpCookie是Cookie的载体,带有Cookie的name,path,value,domain值
③CookiePolicy是Cookie保存规则,来决定当前Cookie是否要保存
④CookieStore则是用来存储Cookie的,也就是存储HttpCookie。
好了,到这里大家已经知道了要如何去保存Cookie了吧,也就可以自己尝试去封装HttpUrlConnection了。
这是我自己简单封装了HttpURLConnection方法
有:
* 封装了get和post方法的请求
* 请求参数的封装PostBody
* 设置了Cookie的自动保存
* 获取过程中可以选择是否带进度监听
* 请求参数的封装PostBody
* 设置了Cookie的自动保存
* 获取过程中可以选择是否带进度监听
NetworkUtil.getInstance().get("http://www.baidu.com", new ResultListener() { @Override public void onResultSuccess(String success) { Log.e(TAG, "onResultSuccess: " + success); } @Override public void onResultFail(String fail) { Log.e(TAG, "onResultFail: " + fail); } });
地址: https://github.com/ZengZeHong/NetworkUtil
感兴趣的可以看下。
参考资料:
谷歌官方API:https://developer.android.com/reference/java/net/CookieManager.html
1 0
- 教你认清HttpURLConnection里面的CookieManager,CookieStore,CookieHandler,HttpCookie,CookiePolicy
- android-CookieHandler、CookieManager
- asynchttp里面的cookiestore
- HttpURLConnection CookieManager Post提交
- AsyncHttpClient的CookieStore问题
- AsyncHttpClient的CookieStore问题
- CookieManager
- 好好认清你的有毒朋友
- 教你认清MVC,MVP和MVVM
- 教你认清MVC,MVP和MVVM
- 教你认清MVC,MVP和MVVM
- 教你认清MVC,MVP和MVVM
- 教你认清MVC,MVP和MVVM
- 教你认清MVC,MVP和MVVM
- HttpCookie
- HttpCookie
- HttpURLConnection与 CookieManager 实现Post提交请求和Cookie管理
- cookieStore的cookie过期限制
- 第4周项目2 长方形面积
- Ubuntu16.04 apache2配置虚拟主机
- PHP的serialize序列化数据与JSON格式化数据
- 使用RecycleView和SearchView总结(一)
- WebRTC工具`gn`简介
- 教你认清HttpURLConnection里面的CookieManager,CookieStore,CookieHandler,HttpCookie,CookiePolicy
- SparkSql寻医问药问答分析第二次分析
- PHP实现发红包程序
- 312. Burst Balloons 难度:hard 类别:分治、动态规划
- Compiler optimization levels and the debug view
- 启动maven nexus3时遇到的"诡异"异常
- 读[Collection接口和Map接口的主要实现类]小结
- BAT文件的妙用
- 编写hashCode()的基本指导