Android cookieManager & OKHttp以及EasyPlayerPro的媒体流的认证的实现
来源:互联网 发布:阿里云关机还收费吗 编辑:程序博客网 时间:2024/06/14 08:49
Android通过CookManager来管理Cookie。在发送\响应过一个HTTP请求之后,
CookManager首先将响应里的Set-cookie字段parse成一个Cookie列表,并存储到本地;然后每次请求时,都从本地获取到这个Cookie列表,并将其组装成字符串(Cookie=”’),设到请求的header里。
- OKHttp发送请求时从本地读取Cookie并添加到请求的Header里:
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());if (!cookies.isEmpty()) { requestBuilder.header("Cookie", cookieHeader(cookies));}
最终组成的HTTP header里的Cookie内容,即cookieHeader(cookies)的返回值类似如下格式:
io=UBoJHl_2LzpacG6gAAOS; connect.sid=s%3AQzYtBFCTyCKZdZT2EHZZasQIZEIE1fXz.9Lsgche%2ByEslmlsI9j1wjUGEQvCXOl0sIn0DrvKS0fk
在HTTP响应返回后,OKHttp会解析服务器返回的Set-Cookie,并存储到本地。
- OKHttp接收到响应后将Cookie保存下来.HttpHeaders.receiveHeaders
public static void receiveHeaders(CookieJar cookieJar, HttpUrl url, Headers headers) { if (cookieJar == CookieJar.NO_COOKIES) return; List<Cookie> cookies = Cookie.parseAll(url, headers); if (cookies.isEmpty()) return; cookieJar.saveFromResponse(url, cookies); }
- Cookie.parseAll:
/** Returns all of the cookies from a set of HTTP response headers. */ public static List<Cookie> parseAll(HttpUrl url, Headers headers) { List<String> cookieStrings = headers.values("Set-Cookie"); List<Cookie> cookies = null; for (int i = 0, size = cookieStrings.size(); i < size; i++) { Cookie cookie = Cookie.parse(url, cookieStrings.get(i)); if (cookie == null) continue; if (cookies == null) cookies = new ArrayList<>(); cookies.add(cookie); } return cookies != null ? Collections.unmodifiableList(cookies) : Collections.<Cookie>emptyList(); }
可见Cookie.parseAll会从header里取出Set-Cookie,并parse成一个Cookie列表返回。注意这里可能有多个Cookie,比如如下情况:
- 多个Cookie
set-cookie=[connect.sid=s%3AppUUhZKKrfLTG5VSXwKzmwRukTurkqZe.yMBYSkgDwR%2Buci1cdpQYhRLdAgYHrescudjAC88pxHs; Path=/; Expires=Thu, 08 Jun 2017 11:44:44 GMT; HttpOnly, connect.sid=s%3AFVird0AnMWAtTPvl1fPQXBiNpUUIj3jX.KjX%2Fw435wY1B8L6eUCMYQ4Yl5j5S0U9IYoKWvGW2iVU; Path=/; Expires=Wed, 07 Jun 2017 11:54:42 GMT]
接下来,将列表的Cookie持久化.调用saveFromResponse函数.
- cookieJar.saveFromResponse
@Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) { if (cookieHandler != null) { List<String> cookieStrings = new ArrayList<>(); for (Cookie cookie : cookies) { cookieStrings.add(cookie.toString(true)); } Map<String, List<String>> multimap = Collections.singletonMap("Set-Cookie", cookieStrings); try { cookieHandler.put(url.uri(), multimap); } catch (IOException e) { Platform.get().log(WARN, "Saving cookies failed for " + url.resolve("/..."), e); } } }
这个函数里又绕了个弯路,把List转成了Map,并存储到CookieHandler里面.参考cookieHandler.put(url.uri(), multimap);
- cookieHandler.put(url.uri(), multimap);
// 又把map转成HttpCookie ListList<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); }}
这个函数里根据Cookie本身的特性以及持久化策略来决定是否保存cookie.如果保存的话,最终保存到了CookieStore里.
A CookieStore object represents a storage for cookie. Can store and retrieve cookies.
CookieManager will call CookieStore.add to save cookies for every incoming HTTP response, and call CookieStore.get to retrieve cookie for every outgoing HTTP request. A CookieStore is responsible for removing HttpCookie instances which have expired.
CookieStore负责为外部提供Set\Get Cookie的接口,并且在Cookie过期时删除Cookie.我们可继承该Cookie用以实现Cookie的自定义存储策略.比如需要进行重定向业务时,类似于客户端首先向服务器A请求,A可能会向B请求,并把B的响应再响应给客户端.此后客户端再直接向B请求.那我们客户端就可以把第一步响应的Cookie存储下来,做个偷梁换柱,作为B服务器的Cookie,后续向B请求时使用.
// A服务器的相应Headers headers = response.headers();Map<String, List<String>> headersValue = headers.toMultimap();CookieManager cm = (CookieManager) CookieHandler.getDefault();// b_url是B服务器的http地址。// 下面的代码相当于一个“偷梁换柱”的实现// 把A服务器的响应当成是B服务器的响应,存到CookieStore里。cm.put(cookiesUri(URI.create(b_url)), headersValue);
这里同时需要A服务器响应给客户端的HTTP header里附带着B服务器的Set-Cookie头。
总之,以上方案有一定的现实意义,可以实现A服务器完成认证后,在B服务器同时认证的功能,十分适用于流媒体行业。通常流媒体行业都有专门的CMS管理服务器与流分发服务器,而客户端在CMS认证成功后,再向流媒体服务器请求时,没必要再去认证一遍。
作为一款NB的播放器,EasyPlayerPro,就用到了该方案。其在CMS请求成功后,获取一系列媒体流的链接。在后续播放时,通过将之前的Cookie设置到媒体流的请求的Header里,以实现在流分发服务器端的认证。
EasyPlayerPro下载地址:https://fir.im/EasyPlayerPro
相关介绍见:http://www.easydarwin.org/article/news/117.html
- Android cookieManager & OKHttp以及EasyPlayerPro的媒体流的认证的实现
- Android_开发 Android中CookieManager的底层实现
- Android 的WebView使用CookieManager崩溃的问题
- Android 媒体键监听以及模拟媒体键盘的实现 demo
- EasyPlayerPro基于FFMPEG实现播放同时进行录像的功能
- EasyPlayerPro(Windows)开发系列之快放慢放的实现
- android 媒体OMX的实现(硬解码)
- 使用okhttp忽略https的证书认证
- Retrofit+OKHttp实现缓存以及遇到的问题
- android OkHttp的使用
- android OkHttp的使用
- Android OkHttp的封装
- okhttp的使用以及简单的封装
- 关于OKHttp的Https的认证问题(全部信任)
- android支持MMS媒体流的网络电台
- 在EasyPlayerPro上实现一键平稳切换视频源的功能
- OkHttp的一些实现细节
- okhttp拦截器的实现
- ownCloud10BUG问题 – PHP is apparently set up to strip inline doc blocks...
- IntelliJ Idea Eclipse
- Python--序列学习(三)--元组
- SSH密钥登录远程主机
- struts2中Action配置之注解配置
- Android cookieManager & OKHttp以及EasyPlayerPro的媒体流的认证的实现
- Python--序列学习(四)--字典
- 2017.7.8 & numpy基础
- ORA-28040: No matching authentication protocol
- React Native学习笔记(3)--TextInput组件
- HTML5基础知识
- Tensorflow-基本操作基本知识
- 接口到底有什么用
- 剑指offer-13-反转链表