現(xiàn)在每篇文章前都會吐槽下自己的生活事情,也當作個記錄,本來想寫這篇博客很久的了,看標題就知道,想 11 月 7 日就開始寫的了,可是現(xiàn)在(2016年11月27日22:45:12)還沒寫完,因為這段事件趕公司的即時聊天的項目,還有每個星期都會來一篇算法的文章或做算法的題,因此導致這篇文章很久還沒寫完,不想拖下去,趕緊寫完。
一、 OKHttp基礎(chǔ)
我們可以通過右鍵 new——》Module——》java Library 的方式來創(chuàng)建一個 Module 的方式來測試一下 OKHttp3 ,為什么是創(chuàng)建 java Library 呢?因為對于一般的網(wǎng)絡框架而已,我們只需要創(chuàng)建 java Library就可以了,不必要創(chuàng)建 Android Library 。
然后導入我們的OKHttp3,具體的官網(wǎng)在之前的系列文章中就有個介紹:
CSDN:http://blog.csdn.net/Two_Water/article/details/53055524
簡書:http://www.itdecent.cn/p/049a91e9958a
1.同步請求和異步請求
創(chuàng)建完項目后,來了解一下OKHttp3的同步請求和異步請求,雖然官網(wǎng)就有很詳細的例子,可是最好還是自己讀嘗試一次,就算是跟著官網(wǎng)的例子敲一遍,還是有一番體會的。
package com.liangdianshui.http.lib;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* OKHttp 同步請求和異步請求
*
* Created by liangdianshui on 2016/11/8
*/
public class SendRequest {
/**
* 同步請求
* <p>
* 會阻塞當前線程
* </p>
*
* @param url
*/
public static void sendRequest(String url) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
System.out.println(response.body().string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 異步請求
*
* @param url
*/
public static void sendAsyncRequest(String url) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
System.out.println(Thread.currentThread().getId());
}
}
});
}
public static void main(String args[]) {
sendRequest("http://blog.csdn.net/two_water");
System.out.println("-------------------------------------------");
System.out.println(Thread.currentThread().getId());
sendAsyncRequest("http://blog.csdn.net/two_water");
}
}
2.請求頭和響應頭
在上一個博客中也有介紹到響應頭和請求頭,也介紹了一大堆參數(shù),那么我們?nèi)绾问褂眠@些參數(shù)呢?
package com.liangdianshui.http.lib;
import java.io.IOException;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* 增加請求頭的請求
* Created by liangdianshui on 2016/11/8
*/
public class AddHeaderRequest {
public static void addHeaderRequest(String url) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.addHeader("User-Agent", "liangdianshui")
.build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
Headers requestHeaders = request.headers();
System.out.println("----------Request Headers------------");
for (int i = 0; i < requestHeaders.size(); i++) {
System.out.println(requestHeaders.name(i) + " : " + requestHeaders.value(i));
}
Headers responseHeaders = response.headers();
System.out.println("------------Response Headers-----------");
for (int i = 0; i < responseHeaders.size(); i++) {
System.out.println(responseHeaders.name(i) + " : " + responseHeaders.value(i));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
addHeaderRequest("http://blog.csdn.net/two_water");
}
}
我們也可以通過 Fiddler 來查看到我們請求中的請求頭的,合理使用這些工具可以驗證我們獲取的數(shù)據(jù)是否正確,少走一些彎路
3.添加請求參數(shù)的get請求
請求參數(shù)的 get 請求,我們使用和風網(wǎng)的免費天氣查詢 api 作為例子,和風網(wǎng)的官網(wǎng)地址:
我們首先的注冊一個用戶,就會分配key:
注冊完成后我們就可以去查找相關(guān)的API文檔,看看如何調(diào)用:
最后就是上代碼了:
package com.liangdianshui.http.lib;
import java.io.IOException;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* 添加請求參數(shù)的get請求
* <p>
* Created by Administrator on 2016/11/16 0016.
*/
public class AddQueryParameterRequest {
/**
* 使用和風網(wǎng)的免費天氣查詢的api
*/
public static void addQueryParameterRequest() {
OkHttpClient client=new OkHttpClient();
HttpUrl httpUrl=HttpUrl.parse("https://free-api.heweather.com/v5/now")
.newBuilder()
.addQueryParameter("city","shenzhen")
.addQueryParameter("key"," 9b82700caecd4d3aa709c54a7593754d")
.build();
Request request=new Request.Builder().url(httpUrl.toString()).build();
try {
Response response=client.newCall(request).execute();
if (response.isSuccessful()) {
System.out.println(response.body().string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
addQueryParameterRequest();
}
}
4.post請求
如果使用公共的 api 提交 post 請求,相對于 get 請求來說,是相對麻煩一些的,因此我們自己寫一個簡單的服務,來請求 post 請求,
服務器的代碼主要是這個:
客戶端代碼:
package com.liangdianshui.http.lib;
import java.io.IOException;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* Created by liangdianshui on 2016/11/27 0027.
*/
public class PostRequest {
public static void postRequest(String url, String name, String password) {
OkHttpClient client = new OkHttpClient();
FormBody body = new FormBody.Builder().add("username", name).add("password", password).build();
Request request = new Request.Builder().url(url).post(body).build();
try {
Response reponse = client.newCall(request).execute();
if (reponse.isSuccessful()) {
System.out.println(reponse.body().string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
postRequest("http://localhost:8080/OKHttpTest/OKHttpPost", "liangdianshui", "123456");
}
}
運行的結(jié)果:
在這里呢,我們先了解一個知識點:
可以看到 post 請求中默認的類型就是:application/x-www-form-urlencoded 因此我們可以查看下我們 OKHttp 中的 FormBody 中的源碼:
可以看到我們使用的 FormBody 就是這個類型的,而 multipart/form-data 這個類型主要是用于上傳文件等相關(guān)操作的。因為這個上傳方式不做編碼處理,你上傳什么就是什么
5.上傳文件
這里我們先寫一下服務器的代碼,也要了解一下到底 http 是怎樣上傳文件的
先寫一個 html 的頁面:
然后我們看下服務器的代碼,寫的非常的簡單,主要是我們只是了解下上傳文件的流程而已。
我們來看下效果:
好了,服務器完成了,我們來查看一下上傳文件的協(xié)議是怎樣的:
可以看到,如果我們自己寫上傳文件的代碼還是比較復雜的,只不過這里面的過程,OKHttp 都幫我們封裝好了,因此使用起來還是比較簡單的。
package com.liangdianshui.http.lib;
import java.io.File;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by liangdianshui on 2016/11/28 0028.
*/
public class MultiparHttp {
public static void main(String args[]) {
//上傳一張本地的圖片
RequestBody imageBody = RequestBody.create(MediaType.parse("image/jpeg"), new File("C:\\Users\\Administrator\\Desktop\\service\\liangdianshui.jpg"));
MultipartBody body = new MultipartBody.Builder().
setType(MultipartBody.FORM). //要配置上傳的類型,否則會上傳不成功
addFormDataPart("name", "nate").
addFormDataPart("filename", "girl.jpg", imageBody).build();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().
url("http://localhost:8080/OKHttpTest/UploadServlet").post(body).build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
System.out.println(response.body().string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
運行的結(jié)果:
6. Http 緩存
其實 OkHttp 給我們封裝好了 Http 的緩存,用起來還是挺方便的,可是我們不能僅限于在用,先不說我們要創(chuàng)造屬于自己的藝術(shù)品,起碼我們得知其所以然,只有這樣,才能有利于我們技術(shù)的進階。竟然說到 Http 的緩存,那么我們必需得問,為什么要有 Http 請求緩存呢?每個設計肯定有它的思想所在,我們得理解,得探討。
為什么要有 Http 請求的緩存?
(1)快: 緩存緩解了網(wǎng)絡瓶頸的問題,不需要更多的網(wǎng)絡帶寬就能更快的加載頁面。
(2)省:緩存減少了冗余的數(shù)據(jù)傳輸,節(jié)省了網(wǎng)絡費用。
(3)低:緩存降低了對原始服務器的要求,服務器可以更快的響應。同時,搜索引擎的爬蟲機器人也能根據(jù)過期機制降低爬取的頻率,也能有效降低服務器的壓力。
當然 Http 請求緩存給我們帶來了一系列的好處之外,也有它的不足,那么它有什么不足或缺點呢?
(1)占空間:緩存沒有清理機制,這些緩存的文件會永久性地保存在機器上,在特定的時間內(nèi),這些文件可能是幫了你大忙,但是時間一長,我們已經(jīng)不再需要瀏覽之前的這些網(wǎng)頁,這些文件就成了無效或者無用的文件,它們存儲在用戶硬盤中只會占用空間而沒有任何用處,如果要緩存的東西非常多,那就會撐暴整個硬盤空間。
(2)不即現(xiàn):因為緩存,有時候我們明明修改了樣式文件、圖片、視頻或腳本,刷新頁面或部署到站點之后看不到修改之后的效果。所以在產(chǎn)品開發(fā)的時候我們總是想辦法避免緩存產(chǎn)生,而在產(chǎn)品發(fā)布之時又在想策略管理緩存提升網(wǎng)頁的訪問速度。這就給我們帶來了一定的困擾。
那么是怎樣實現(xiàn) Http 的緩存的呢?
其實 Http 緩存在不同的類型上緩存的方式不一樣,可是原理還是一樣的,我們通過了解瀏覽器緩存來探討一下是怎樣實現(xiàn)的?
Http 請求緩存中相關(guān)的字段有哪些呢?
最后通過請求我的博客來看一下緩存:
其中:
Cache-control 常見的取值有 private、no-cache、max-age、must-revalidate 等,默認為private 。其作用根據(jù)不同的重新瀏覽方式分為以下幾種情況:
(1) 打開新窗口
如果指定 cache-control 的值為 private、no-cache、must-revalidate,那么打開新窗口訪問時都會重新訪問服務器。而如果指定了 max-age 值,那么在此值內(nèi)的時間里就不會重新訪問服務器,例如:
Cache-control: max-age=5
表示當訪問此網(wǎng)頁后的5秒內(nèi)再次訪問不會去服務器
(2) 在地址欄回車
如果值為 private 或 must-revalidate(和網(wǎng)上說的不一樣),則只有第一次訪問時會訪問服務器,以后就不再訪問。如果值為 no-cache,那么每次都會訪問。如果值為 max-age ,則在過期之前不會重復訪問。
(3) 按后退按扭
如果值為 private、must-revalidate、max-age,則不會重訪問,而如果為 no-cache,則每次都重復訪問
(4) 按刷新按扭
無論為何值,都會重復訪問
最后我們來看下 OKHttp 是如何設置緩存的:
/**
* 請求一個網(wǎng)址,設置緩存
* <p>要進行緩存,首先網(wǎng)址的服務器端先要支持緩存,再者,我們可以通過
* @code:{ public Builder cacheControl(CacheControl cacheControl) } 的方式控制客戶端的緩存</p>
*
* @param url
* @param file
* @param maxCacheSize
* @throws IOException
*/
public static void cachRequest(String url, File file, int maxCacheSize) throws IOException {
Cache cache = new Cache(file, maxCacheSize);
OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();
Request request = new Request.Builder().url(url).build();
Response response = client.newCall(request).execute();
String body = response.body().string();
}
想了解 OKHttp 是如何實現(xiàn)緩存的,我們可以先從 OKHttp 整個的流程圖中入手:
本來還想寫完緩存的分析的,可是看了下時間(2016年11月29日01:25:49)已經(jīng)很晚了,還是睡了,明天還得上班,其實 OKHttp 緩存的實現(xiàn)看了很久源碼,里面一大堆的 if 判斷,看的有點暈,不過整體大概的原理還是可以理解的,細節(jié)的部分就略過了。哎,總是對自己那么仁慈,可能這就是跟大神的距離了。