參考:
整體代碼與示例故响,請參考:
https://github.com/zhaoyubetter/basenet
至此網(wǎng)絡(luò)模塊的封裝告一段落肮帐;
為什么需要POST緩存
大環(huán)境所致龄毡,在servlet中,有2個方法悼潭,分別是 doGet, doPost潮酒,要么在 doGet中,轉(zhuǎn)發(fā)到了doPost磨镶,要么反之溃蔫,springMVC,已記不清了。
所以這就造成了琳猫,有時候伟叛,我們真的需要 為 post添加緩存;
為post請求添加緩存原理
參考圖片:
在 application 級別攔截請求脐嫂,因為:應(yīng)用攔截器允許短路而不調(diào)用 Chain.proceed(),即中止調(diào)用
判斷如果是 post统刮,如果緩存有效,直接返回response账千,讓后續(xù)的攔截器無法執(zhí)行侥蒙;
其他緩存的內(nèi)容,幾乎都是 Cache.java那套匀奏;少量修改鞭衩;
圖片來自網(wǎng)絡(luò)
具體實現(xiàn):
-
為 OkhttpClient添加應(yīng)用攔截器:
final OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.connectTimeout(NetConfig.getInstance().getTimeOut(), TimeUnit.MILLISECONDS); builder.readTimeout(NetConfig.getInstance().getTimeOut(), TimeUnit.MILLISECONDS); builder.writeTimeout(NetConfig.getInstance().getTimeOut(), TimeUnit.MILLISECONDS); /* ==設(shè)置攔截器== */ // 設(shè)置緩存 File cacheDir = new File(NetConfig.getInstance().getCacheDir()); // GET 形式緩存設(shè)置 Cache cache = new Cache(cacheDir, NetConfig.getInstance().getCacheSize()); builder.cache(cache).addNetworkInterceptor(new NetCacheInterceptor()); // 設(shè)置緩存攔截器 // 日志攔截 if (NetConfig.getInstance().isDebug()) { builder.addInterceptor(new LoggerInterceptor()); } // 是否允許POST 形式緩存設(shè)置 if (NetConfig.getInstance().isEnablePostCache()) { builder.addInterceptor(new PostCacheInterceptor()); }
新增類 NetPostCache.java, 此類,就是 copy 了 Cache類攒射,然后修改
其put方法醋旦,讓其支持post,與 獲取key方法会放,如下:
public static String key(Request request) {
String cUrl = request.url().toString();
if (request.body() != null) {
Buffer buffer = new Buffer();
try {
// 避免post重復(fù)饲齐,這里采用value來憑借,因key不好獲取
// 如果有上傳下載文件咧最,此處為 ProgressRequestBody
if (request.body() instanceof MultipartBody) {
final List<MultipartBody.Part> parts = ((MultipartBody) request.body()).parts();
/**
* 接受字符串格式的參數(shù)捂人,其他忽略
* @see lib.basenet.okhttp.OkHttpRequest#getRequestBody mParams
*/
for (MultipartBody.Part p : parts) {
if (null == p.body().contentType()) {
p.body().writeTo(buffer);
}
}
}
String params = buffer.readString(Charset.forName("UTF-8")); //獲取請求參數(shù)
cUrl += params;
} catch (IOException e) {
e.printStackTrace();
} finally {
Util.closeQuietly(buffer);
}
}
return ByteString.encodeUtf8(cUrl).md5().hex();
}
- 應(yīng)用級攔截器:PostCacheInterceptor.java 代碼片段
/**
* post緩存御雕,從應(yīng)用攔截器層,攔截
* Created by zhaoyu on 2017/4/26.
*/
public class PostCacheInterceptor implements Interceptor {
/**
* 緩存Post請求
*/
final NetPostCache mPostCache;
public PostCacheInterceptor() {
File cacheDir = new File(NetConfig.getInstance().getCacheDir() + "/post");
mPostCache = new NetPostCache(cacheDir, NetConfig.getInstance().getCacheSize());
}
@Override
public Response intercept(Chain chain) throws IOException {
final Request request = chain.request();
// 如果是post請求滥搭,并且設(shè)置了緩存酸纲,則在這里進(jìn)行攔截,如果緩存有效瑟匆,后續(xù)的攔截器將不執(zhí)行
if ("POST".equalsIgnoreCase(request.method()) && (null != request.cacheControl() && !request.cacheControl().noStore())) {
// 強制刷新闽坡,刪除舊有post緩存
checkForceRefresh(request);
// 以下代碼邏輯來家:okhttp3 源碼中的 CacheInterceptor.java,模擬其運行
Response cacheCandidate = mPostCache != null ? mPostCache.get(request) : null;
long now = System.currentTimeMillis();
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
if (mPostCache != null) {
mPostCache.trackResponse(strategy);
}
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body()); // The mPostCache candidate wasn't applicable. Close it.
}
// 有則從緩存中返回愁溜,直接跳過后面的攔截器疾嗅,不訪問網(wǎng)絡(luò)了
// If we don't need the network, we're done.
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
Response networkResponse = null;
try {
// 執(zhí)行網(wǎng)絡(luò)請求,并包裝一下
networkResponse = chain.proceed(request);
} finally {
// If we're crashing on I/O or otherwise, don't leak the mPostCache body.
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
if (HttpHeaders.hasBody(networkResponse)) {
CacheRequest cacheRequest = mPostCache.put(networkResponse);
networkResponse = cacheWritingResponse(cacheRequest, networkResponse);
}
// 當(dāng) onSuccess調(diào)用時冕象,會寫入緩存
return networkResponse;
}
return chain.proceed(request);
}
注意事項:
post 緩存時代承,因 唯一key,不好定位渐扮,只支持 請求參數(shù)為 鍵值對(key-value)form 表單形式论悴,對于上傳文件,下載文件形式的post墓律,請求膀估,一律無效;