OkHttp3入门介绍之Cookie持久化
版权所有,转载请注明出处:linzhiyong https://juejin.im/post/5b596f315188251aef4e683c https://www.jianshu.com/p/23b35d403148
相关文章
1、OkHttp3入门介绍
2、OkHttp3入门介绍之Cookie持久化
前面文章介绍了OkHttp3的基本用法,GET/PST请求、上传下载文件等等,本章节主要介绍基于内存和本地缓存的Cookie管理。 官网:http://square.github.io/okhttp/目录 本章主要从以下几个方面介绍:
Github:https://github.com/square/okhttp
OkHttp3Demo传送门:https://github.com/linzhiyong/OkHttp3Demo
服务端Demo传送门:https://github.com/linzhiyong/SpringMVCDemo
1、OkHttp3 Cookie内置管理机制介绍
2、基于本地存储的Cookie管理
3、基于内存存储的Cookie管理
4、总结
1、OkHttp3 Cookie内置管理机制介绍 OkHttp提供了用于管理Cookie的接口
CookieJar
,看一下接口的内部结构:public interface CookieJar {
/** 内部默认实现,不做任何操作. */
CookieJar NO_COOKIES = new CookieJar() {
@Override public void saveFromResponse(HttpUrl url, List cookies) {
}@Override public List loadForRequest(HttpUrl url) {
return Collections.emptyList();
}
};
/** 调用网络请求,获取到cookie相关信息后,okhttp会回调该方法,此处可以缓存或者持久化cookie */
void saveFromResponse(HttpUrl url, List cookies);
/** 请求时,okhttp会通过该方法,获取对应的cookie */
List loadForRequest(HttpUrl url);
}
复制代码
从上面可以看出,
CookieJar
接口提供了saveFromResponse
、loadForRequest
两个方法,还有一个内部类默认实现NO_COOKIES
。 1)saveFromResponse
方法:当网络请求返回结果后,内部会解析Header并获取cookie相关信息,同时回调该方法,此处可以缓存或者持久化cookie,下面看一下调用源码:public final class BridgeInterceptor implements Interceptor {
// 此处省略
@Override public Response intercept(Chain chain) throws IOException {
// 此处省略...// 通过cookieJar接口的loadForRequest方法获取url对应的cookie
List cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
// 如果获取到的cookie不为空,则设置到请求头中
requestBuilder.header("Cookie", cookieHeader(cookies));
} // 此处省略
}
}
复制代码
2)
loadForRequest
方法:当网络请求时,okhttp会通过该方法,获取对应cookie,下面看一下调用源码:public final class BridgeInterceptor implements Interceptor {
// 此处省略
@Override public Response intercept(Chain chain) throws IOException {
// 此处省略...// 此处获取请求的响应对象
Response networkResponse = chain.proceed(requestBuilder.build());
// 解析响应头里的信息
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
}
}public final class HttpHeaders {public static void receiveHeaders(CookieJar cookieJar, HttpUrl url, Headers headers) {
if (cookieJar == CookieJar.NO_COOKIES) return;
// 解析响应头里的信息
List cookies = Cookie.parseAll(url, headers);
if (cookies.isEmpty()) return;
// 调用cookieJar接口的saveFromResponse方法,下发cookie
cookieJar.saveFromResponse(url, cookies);
}}
复制代码
3)如果开发者在初始化
OkHtpClient
时没有自定义CookieJar,默认不会进行cookie操作,看一下OkHttpClient
的构造器实现;public static final class Builder {
CookieJar cookieJar;
public Builder() {
// 默认使用自带cookie管理器,没有做任何cookie处理
cookieJar = CookieJar.NO_COOKIES;
}
}
复制代码
2、基于本地存储的Cookie管理 这里我仿照 android-async-http 的Cookie管理机制
PersistentCookieStore
进行改造;实现逻辑 1、定义用于管理Cookie的接口
CookieStore
;
2、定义CookieJarImpl
类实现CookieJar
接口,然后用CookieStore
去接管saveFromResponse
、loadForRequest
这两个方法; 3、定义PersistentCookieStore
类实现CookieStore
接口,用于管理Cookie; 4、将PersistentCookieStore
对象设置到OkHttpClient
中;具体实现 1、定义
CookieStore
接口:/**
* Cookie缓存接口
*
* @author linzhiyong
* @email wflinzhiyong@163.com
* @blog https://blog.csdn.net/u012527802
* @desc
*/
public interface CookieStore {/**添加cookie */
void add(HttpUrl httpUrl, Cookie cookie);
/** 添加指定httpurl cookie集合 */
void add(HttpUrl httpUrl, List cookies);
/** 根据HttpUrl从缓存中读取cookie集合 */
List get(HttpUrl httpUrl);
/** 获取全部缓存cookie */
List getCookies();
/**移除指定httpurl cookie集合 */
boolean remove(HttpUrl httpUrl, Cookie cookie);
/** 移除所有cookie */
boolean removeAll();
}
复制代码
2、定义
CookieJarImpl
类实现CookieJar
接口,然后用CookieStore
去接管saveFromResponse
、loadForRequest
这两个方法:/**
* CookieJarImpl
*
* @author linzhiyong
* @email wflinzhiyong@163.com
* @blog https://blog.csdn.net/u012527802
* @time 2018/7/20
* @desc
*/
public class CookieJarImpl implements CookieJar {private CookieStore cookieStore;
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 cookies) {
this.cookieStore.add(url, cookies);
}@Override
public synchronized List loadForRequest(HttpUrl url) {
return this.cookieStore.get(url);
}public CookieStore getCookieStore() {
return this.cookieStore;
}
}
复制代码
3、定义
PersistentCookieStore
类实现CookieStore
接口,用于管理Cookie; (注:这里仿照android-async-http库里的 PersistentCookieStore 实现)/**
* Cookie缓存持久化实现类
*
* @author linzhiyong
* @email wflinzhiyong@163.com
* @blog https://blog.csdn.net/u012527802
* @time 2018/7/20
* @desc
*/
public class PersistentCookieStore implements CookieStore {private static final String LOG_TAG = "PersistentCookieStore";
private static final String COOKIE_PREFS = "CookiePrefsFile";
private static final String HOST_NAME_PREFIX = "host_";
private static final String COOKIE_NAME_PREFIX = "cookie_";
private final HashMap> cookies;
private final SharedPreferences cookiePrefs;
private boolean omitNonPersistentCookies = false;
/** Construct a persistent cookie store.*/
public PersistentCookieStore(Context context) {
this.cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0);
this.cookies = new HashMap>();
Map tempCookieMap = new HashMap
这里面用到了
SerializableCookie
,主要用于序列表cookie对象到对象流中:/**
* 仿照android-async-http的SerializableCookie实现,用处是cookie对象与对象流的互转,保存和读取cookie
*
* @author linzhiyong
* @email wflinzhiyong@163.com
* @blog https://blog.csdn.net/u012527802
* @time 2018/7/20
* @desc
*/
public class SerializableCookie implements Serializable {
private static final long serialVersionUID = 6374381828722046732L;
private transient final Cookie cookie;
private transient Cookie clientCookie;
public SerializableCookie(Cookie cookie) {
this.cookie = cookie;
}public Cookie getCookie() {
Cookie bestCookie = cookie;
if (this.clientCookie != null) {
bestCookie = this.clientCookie;
}
return bestCookie;
}/** 将cookie写到对象流中 */
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeObject(this.cookie.name());
out.writeObject(this.cookie.value());
out.writeLong(this.cookie.expiresAt());
out.writeObject(this.cookie.domain());
out.writeObject(this.cookie.path());
out.writeBoolean(this.cookie.secure());
out.writeBoolean(this.cookie.httpOnly());
out.writeBoolean(this.cookie.hostOnly());
out.writeBoolean(this.cookie.persistent());
}/** 从对象流中构建cookie对象 */
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
String name = (String) in.readObject();
String value = https://www.it610.com/article/(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()
.name(name)
.value(value)
.expiresAt(expiresAt)
.path(path);
builder = hostOnly ? builder.hostOnlyDomain(domain) : builder.domain(domain);
builder = secure ? builder.secure() : builder;
builder = httpOnly ? builder.httpOnly() : builder;
this.clientCookie = builder.build();
}
}
复制代码
4、将
PersistentCookieStore
对象设置到OkHttpClient
中;OkHttpClient.Builder builder = new OkHttpClient.Builder()
.cookieJar(new CookieJarImpl(new PersistentCookieStore(context)));
复制代码
3、基于内存存储的Cookie管理 实现逻辑跟
PersistentCookieStore
类似,只是对于Cookie的存储放在了Map中。/**
* Cookie内存缓存实现
*
* @author linzhiyong
* @email wflinzhiyong@163.com
* @blog https://blog.csdn.net/u012527802
* @time 2018/7/20
* @desc
*/
public class MemoryCookieStore implements CookieStore {private static final String HOST_NAME_PREFIX = "host_";
private static final String COOKIE_NAME_PREFIX = "cookie_";
private final HashMap> cookies;
public MemoryCookieStore() {
this.cookies = new HashMap>();
}@Override
public void add(HttpUrl httpUrl, Cookie cookie) {
if (!cookie.persistent()) {
return;
}String name = this.cookieName(cookie);
String hostKey = this.hostName(httpUrl);
if(!this.cookies.containsKey(hostKey)) {
this.cookies.put(hostKey, new ConcurrentHashMap());
}
cookies.get(hostKey).put(name, cookie);
}@Override
public void add(HttpUrl httpUrl, List cookies) {
for (Cookie cookie : cookies) {
if (isCookieExpired(cookie)) {
continue;
}
this.add(httpUrl, cookie);
}
}@Override
public List get(HttpUrl httpUrl) {
return this.get(this.hostName(httpUrl));
}@Override
public List getCookies() {
ArrayList result = new ArrayList();
for (String hostKey : this.cookies.keySet()) {
result.addAll(this.get(hostKey));
}return result;
}/** 获取cookie集合 */
private List get(String hostKey) {
ArrayList result = new ArrayList();
if (this.cookies.containsKey(hostKey)) {
Collection cookies = this.cookies.get(hostKey).values();
for (Cookie cookie : cookies) {
if (isCookieExpired(cookie)) {
this.remove(hostKey, cookie);
}
else {
result.add(cookie);
}
}
}
return result;
}@Override
public boolean remove(HttpUrl httpUrl, Cookie cookie) {
return this.remove(this.hostName(httpUrl), cookie);
}/** 从缓存中移除cookie */
private boolean remove(String hostKey, Cookie cookie) {
String name = this.cookieName(cookie);
if (this.cookies.containsKey(hostKey) && this.cookies.get(hostKey).containsKey(name)) {
// 从内存中移除httpUrl对应的cookie
this.cookies.get(hostKey).remove(name);
return true;
}
return false;
}@Override
public boolean removeAll() {
this.cookies.clear();
return true;
}/** 判断cookie是否失效 */
private boolean isCookieExpired(Cookie cookie) {
return cookie.expiresAt() < System.currentTimeMillis();
}private String hostName(HttpUrl httpUrl) {
return httpUrl.host().startsWith(HOST_NAME_PREFIX) ? httpUrl.host() : HOST_NAME_PREFIX + httpUrl.host();
}private String cookieName(Cookie cookie) {
return cookie == null ? null : cookie.name() + cookie.domain();
}
}
复制代码
4、总结 今天的主要就是介绍了Cookie的管理,就是从
CookieJar
接口的两个方法入手,然后做了进一步的封装处理,PersistentCookieStore
和MemoryCookieStore
这两个类的逻辑实现基本一致,喜欢动手的小伙伴完全可以进一步抽象一下。【OkHttp3入门介绍之Cookie持久化】转载于:https://juejin.im/post/5b596f315188251aef4e683c
推荐阅读
- Apache多路复用模块(MPMs)介绍
- 第十六天(请介绍一件让你非常自豪的事情,(不能是职业类的),什么原因感到自豪。)
- typeScript入门基础介绍
- “我不想努力了,能给我介绍个富婆吗(”)
- 今日自我介绍,感恩所遇一切
- 杨梦彤自我介绍
- 第六章|第六章 Sleuth--链路追踪
- 区块链开发平台(以太坊)
- Android|Android sqlite3数据库入门系列
- trilinos|trilinos 介绍