1、OkHttp的全面用法:html
1. Get的請求: 例子 請求百度java
OkHttpClient client = new OkHttpClient();
HttpUrl httpUrl = HttpUrl.parse("www/baidu.com").newBuilder()
.addQueryParameter("city","beijing")
.build();
Request request = new Request.Builder()
.url(httpUrl)
.build();面試
Response response = client.newCall(request).execute();算法
2. 異步POST請求 FormBody編程
OkHttpClient client = new OkHttpClient();
FormBody body = new FormBody.Builder()
.add("name","xiaoming")
.add("age","18")
.build();
Request request = new Request.Builder()
.url("www/baidu.com")
.post(body)
.build();
Response response = client.newCall(request).execute();
3. 異步上傳文件 MultipartBodyjson
MediaType MEDIA_TYPE = MediaType.parse("text/x-markdown; charset=utf-8");
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/nihao.txt";
File file = new File(path);
RequestBody requestBody = RequestBody.create(file,MEDIA_TYPE);
MultipartBody body = new MultipartBody.Builder()
----->上傳字符時候須要加上setType特殊類型,不然沒法上傳成功
.addFormDataPart("filename", "filename", requestBody)
.build();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("www.baidu.com")
.post(body)
.build();
4.異步下載文件
String url = "https://img-my.csdn.net/uploads/201603/26/1458988468_5804.jpg";
final Request request = new Request.Builder().url(url).build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: 失敗");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
InputStream is = response.body().byteStream();
String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/shu.jpg";
File file = new File(path);
FileOutputStream fos = new FileOutputStream(file);
try{
byte[] buffer = new byte[1024];
int len = 0;
while((len = is.read(buffer)) != -1) {
fos.write(buffer,0,len);
}
fos.flush(); //文件的讀寫,這個須要多看看和學習
}catch (Exception e){
e.printStackTrace();
}
Log.d(TAG, "onResponse: --->下載完成");
}
});
2、同步和異步的區別設計模式
裏面有個Dispatcher這個類來實現,它主要做用是維護請求的狀態(同步和異步),而且維護一個線程池,用於執行請求瀏覽器
同步請求緩存
同步請求發送請求以後,就會進入阻塞狀態,Dispatcher(分發器)主要作兩個事情:保存同步請求、移除同步請求,直到收到響應。 服務器
異步請求
異步請求放到線程池裏面,Dispatcher類主要作三件事情:正在執行異步隊列、等待執行異步隊列、維護一個還有一個線程池
裏面之因此有兩個異步請求隊列:當前運行的異步隊列小於64時候,它就會被放入到正在運行的異步隊列(runningAsyncCalls)中,而後去運行線程池,不然就是加入就緒緩衝隊列(readyAsyncCalls)當中做爲等待
3、緩存的原理以及實現
1.緩存原理:
2.緩存相關的字段
Expirse : 緩存失效的時間
Cactce-Contral : 控制緩存 緩存類型
private : 客戶端能夠去緩存
public : 客戶端和代理服務器均可以緩存
max-age : 表示多少秒後失效(在服務端用的較多)
· no-cache : 經過服務驗證碼(304)是否能使用緩存
no-store : 代理和本地都不可使用緩存,只能從服務器去拿數據
Last-Modified : 最後一次修改時間(好比只是添加一個空格,時間就不同,因此就出現ETag這個關鍵字段)
ETag : 經過返回的Response返回數據比較裏面兩個內容是否一直
If-Modified-Since : 與Last-Modified成對存在的
If-None-Match : 與ETag成對存在的
3.緩存的機制
int maxSize = 10 * 1024 * 1024;
Cache cache = new Cache(new File("sd"), maxSize);
OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();
Request request = new Request.Builder()
.url("http://www.qq.com")
.build();
Response response = client.newCall(request).execute();
String string = response.body().toString(); --------->若是你不去讀取返回的Response的請求體,
下次在請求也仍是網絡請求,並非緩存請求
if(response.isSuccessful()){
Log.i(TAG, "run: = " + response.networkResponse().toString());
Log.i(TAG, "run: = " + response.cacheResponse().toString());
Log.i(TAG, "run-------------------------------");
Response response1 = client.newCall(request).execute();
String string = response1.body().toString(); ------>此次再次請求就是緩存請求
if(response1.isSuccessful()){
Log.i(TAG, "run: = " + response1.networkResponse().toString());
Log.i(TAG, "run: = " + response1.cacheResponse().toString());
4. 緩存實現
CacheInterceptor : 緩存攔截器
CasheStrategy : 緩存策略(是用本地緩存仍是網絡緩存),networkResponse爲空的時候執行cacheResponse,不然須要取網絡請求
Cache : 緩存目錄,這裏面就有put get remove等方法進行對緩存的操控
4、多線程下載功能
1.關鍵的字段
Transer-Encoding : chunked : 沒法拿到整個文件的長度
content-length : 訪問文件的總長度的大小
Range : 能夠訪問服務器某一個字段的長度大小
2. 下載文件遇到的問題
文件存儲的路徑 : 檢查是否有SD卡的路徑
文件是否受損 : 經過拿到服務器的文件的MD5,而後去和你本地的MD5作對比觀察是否相等,若是不相等說明文件已經受損
文件空間的大小 : 下載文件是否比剩餘空間小,作一個判斷
進度條的更新 :
數據的保存 :
5、Https使用
1.https加密的常見知識
對稱加密: 祕鑰是相同
非對稱加密: 一個是公鑰,一個是私鑰,公鑰只能用私鑰去解,私鑰只能用公鑰去解
數字證書:
2.SSL/TLS的運行機制 :
a.客戶端會告訴服務端證書(公鑰)、數據加密算法、以及生成一個隨機數
b.服務端接受以後對證書進行私鑰解密,驗證是否可信,若是成功,服務端會確認是使用加密算法、以及生成一個隨機數給客戶端
c.客戶端再對服務端返回數據進行驗證,驗證經過以後就發送對稱加密對數據進行加密處理,發送給服務端
d.服務端就會對稱加密進行解析拿到數據
證書採用的是非對稱加密,而數據傳輸採用的是對稱加密
3.DNS講解 : 域名解析
好比我去直接訪問IP地址,它會拋出校驗拋出的異常,connect請求鏈接時候添加HostnameVerifier這個接口裏面的verify,直接返回爲true,就能夠跳過校驗
class MyHostVerify implements HostnameVerifier() {
@Override
public boolean verify(){
手動能夠去寫校驗方法
return true;
}
}
6、自定義攔截器
1.重寫Interceptor這個類
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
/**
* 重試攔截器
*/
public class RetryIntercepter implements Interceptor {
public int maxRetry;//最大重試次數
private int retryNum = 0;//假如設置爲3次重試的話,則最大可能請求4次(默認1次+3次重試)
public RetryIntercepter(int maxRetry) {
this.maxRetry = maxRetry;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
System.out.println("retryNum=" + retryNum);
Response response = chain.proceed(request);
while (!response.isSuccessful() && retryNum < maxRetry) {
retryNum++;
System.out.println("retryNum=" + retryNum);
response = chain.proceed(request);
}
return response;
}
}
2.添加自定義攔截器
mClient=new OkHttpClient.Builder()
.addInterceptor(new RetryIntercepter(3))//重試
.addInterceptor(logging)//網絡日誌
.addInterceptor(new TestInterceptor())//模擬網絡請求
.build();
3.addInterceptor(添加應用攔截器)和addNetworkInterceptor()的區別
addInterceptor : 老是隻調用一次,即便HTTP響應是從緩存中獲取,不是從網絡獲取的
addNetworkInterceptor : 可以操做中間過程的響應,能夠觀察網絡上傳的數據
6、攔截器總結:
1.應用攔截器和網絡攔截器須要學習
2.攔截器核心原理 :
a. 在發送請求前對Request進行處理
b.調用下一個攔截器獲取response (經過調用realChain.proceed這個方法能夠執行下一個攔截器)
c.對response進行處理,返回給上一個攔截器
7、OkHttp的面試點
1.Socket是什麼?
a.是對TCP/IP協議進行的封的編程接口,類屬於傳輸層
b.成對出現一對套接字 : 包括ip地址和端口號
2. TCP和UDP的區別:
TCP : 基於字節流的方式做爲傳輸
UDP : 基於數據報文格式,打包以後做爲傳輸
3.http和Socket的區別
Http : 採用 請求--響應 方式 。 HTPP協議屬於應用層,客戶端有須要才請求
Socket : 基於TCP/IP協議進行傳輸,採用 服務器主動發送數據 的方式,Socket屬於傳輸層
5. 斷點續傳的原理?(還須要多看看,補充一下)
斷點續傳 : 從文件已經下載的地方開始接着下載
Okhttp中如何實現
Request request = new Request.Builder()
.addHeader("RANGE", "bytes=" + downloadLength + "-")
.url("111111")
.build();
Response response = client.newCall(request).execute();
if(response != null ) {
InputStream is = response.body().byteStream();
saveFile = new RandomAccessFile(file, "rw");
saveFile.seek(downloadLength); //跳過已經下載的字節
byte[] b = new byte[24];
int total = 0;
int len;
while((len = is.read(b)) != -1) {
total += len;
saveFile.write(b, 0, len);
}
}
6.多線程下載原理 okhttp是如何實現的(還須要多看看怎麼使用)
7.json數據如何解析?okhttp如何解析json類型數據
9.okhttp如何處理https
a.https : 是一種基於SSL/TLS的htpp的協議
b.https : 全部傳輸內容都是通過加密的(對稱+不對稱)
對稱加密 : 加密和解密用的是同一個祕鑰(對於真正傳輸數據過程)
非對稱加密 : 加密和解密是偶用的祕鑰不是同一把祕鑰(只是處於握手協議階段)
對稱加密的過程:首先客戶端生成隨機數做爲對稱祕鑰,而後去服務端請求一個公鑰,有服務端返回給客戶端,客戶端接收到公鑰後,使用公鑰對本身生成的對稱祕鑰進行加密,
而後把對稱加密祕鑰加密後的祕鑰在發給服務端,接受到祕鑰它會本身解密,這個時候就能夠數據通訊了。
1、參數的講解
1. OkHttpClient : OkHttp的客戶端,初始化OkHttp的一些重要配置
2. Request : 請求數據封裝
3. Call : 可執行異步或者同步請求
4. Interceptor : OkHttp 中的重要成分,攔截器,基於責任鏈設計模式
5.RetryAndFollowUpInterceptor : 負責錯誤重試以及重定向
6.BridgeInterceptor : 負責組裝請求以及解析數據
7.CacheInterceptor: 負責讀取緩存和更新緩存
8.ConnectInterceptor: 負責和服務器鏈接 Okio對接
9.CallServerInterceptor: 負責發送請求以及接受數據 核心功能
10.攔截器的說明:在RealCall內部維護一個interceptors的集合,經過getResponseWithInterceptorChain去得到originalRequest(原始請求)進行處理,
內部會經過 chain.procee(originalRequest) 最終獲得一個 Response 對象,而 Intercaptor.Chain 內部會封裝當前須要處理的 interceptor 對象。
其內部會調用 interceptor.intercept() 方法去處理這個 request 請求最終獲得 response
· OkHttp同異步大體流程
OkHttp大致流程
2、CacheInterceptor : 負責讀取緩存和更新緩存
1. 案例的使用 : getResponseWithInterceptorChain
裏面調用interceptors.add(new CacheInterceptor(client.internalCache()));
Cache cache = new Cache(new File("/sdcard/test/"),100*100*1024);
OkHttpClient okHttpClient = new OkHttpClient.Builder().cache(cache).build();
Request request = new Request.Builder().url("http://www.imooc.com/courseimg/s/cover005_s.jpg").
cacheControl(new CacheControl.Builder().noCache().build()).build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("info","----onFailure");
}
@Override public void onResponse(Call call, Response response) throws IOException {
Log.e("info","----onResponse"+response.body().toString()); } });
2. okhttp&http緩存策略
1) .強制緩存 : Exprises 、Cache-Control
Exprises :Exprises的值爲服務端返回的到期時間 http1.0用的
Cache-Control : 是服務端返回的Response中添加的頭信息
Cache-Control 的緩存類型 :
private : 客戶端能夠去緩存
public : 客戶端和代理服務器均可以緩存
max-age : 表示多少秒後失效(在服務端用的較多)
· no-cache : 經過服務驗證碼(304)是否能使用本地緩存
no-store : 代理和本地都不可使用緩存,只能從服務器去拿數據
2) . 對比緩存
a. 首先須要進行比較判斷是否可使用緩存
b.服務器會將緩存標識與數據一塊兒返回給客戶端
Etag : 服務器響應請求時,告訴瀏覽器當前資源在服務器的惟一標識
If-None-Match : 再次請求服務器時,經過此字段通知服務器客戶端緩存數據的惟一標識
Last-Modified : 服務器在響應請求時,告訴瀏覽器資源的最後修改時間
If-modified-Since : 再次請求服務器時,經過此字段通知服務器上次請求時,服務器返回的資源最後修改時間
標識發送給服務端,服務端根據緩存標識進行判斷,假如返回304,則表示緩存可用,假如返回200,標識緩存不可用,使用最新返回的數據。
3、BridgeInterceptor
:負責組裝請求以及解析數據 interceptors.add(new BridgeInterceptor(client.cookieJar()));
列舉的是添加的頭信息
Content-Type 定義網絡文件的類型和網頁的編碼,若是未指定 ContentType,默認爲[TEXT]/[HTML],具體的類型,參考這個文檔 HTTP Content-type
Content-Length 表示的是請求體內容的長度。它和 Transfer-Encoding 是互斥的,主要根據 Content-Length 是否爲 -1 進行判讀使用哪個請求頭。
Transfer-Encoding 值爲 chunked 表示請求體的內容大小是未知的。
Host 請求的 url 的主機
Connection 默認就是 "Keep-Alive",就是一個 TCP 鏈接以後不會關閉,保持鏈接狀態
Accept-Encoding 默認是 "gzip" 告訴服務器客戶端支持 gzip 編碼的響應。
Cookie 當請求設置了 Cookie 那麼就是添加 Cookie 這個請求頭。
User-Agent "okhttp/3.4.1" 這個值根據 OKHTTP 的版本不同而不同,它表示客戶端 的信息。
4、retryAndFollowUpInterceptor
: 負責錯誤重試以及重定向 interceptors.add(retryAndFollowUpInterceptor)
1.網絡請求異常的「重連機制」 : 屢次請求,不超過20次,超過20次就不作重複鏈接
2.異常的判斷
a. IOException 異常的重連機制
b.RouteException(路由) 異常的重連機制
c.recover(恢復) 方法異常檢測
d.isRecoverable 方法異常檢測
5、CallServerinterceptor : 負責發送請求以及接受數據 interceptors.add(
new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket())
)
;
1. 寫入請求頭信息和請求體信息
2.得到請求頭和請求體的信息
六、ConnectInterceptor
:負責和服務器鏈接 interceptors.add(new ConnectInterceptor(client));
interceptors.addAll(client.interceptors());
7、自定義攔截器
class LoggingInterceptor implements Interceptor {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
//1.請求前--打印請求信息
long t1 = System.nanoTime();
logger.info(String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
//2.網絡請求 Response response = chain.proceed(request); //3.網絡響應後--打印響應信息 long t2 = System.nanoTime(); logger.info(String.format("Received response for %s in %.1fms%n%s", response.request().url(), (t2 - t1) / 1e6d, response.headers())); return response; } }
1. Application Intercetor和NetworkInterceptor的區別
2.添加Application Interceptor的使用
代碼案例:
OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new LoggingInterceptor()) .build(); Request request = new Request.Builder() .url("http://www.publicobject.com/helloworld.txt") .header("User-Agent", "OkHttp Example") .build(); Response response = client.newCall(request).execute(); response.body().close();
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor()) .build(); Request request = new Request.Builder() .url("http://www.publicobject.com/helloworld.txt") .header("User-Agent", "OkHttp Example") .build(); Response response = client.newCall(request).execute(); response.body().close();
3. NetworkInterceptor 的使用
代碼案例
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new LoggingInterceptor()) .build(); Request request = new Request.Builder() .url("http://www.publicobject.com/helloworld.txt") .header("User-Agent", "OkHttp Example") .build(); Response response = client.newCall(request).execute(); response.body().close();
4. Application Interceptor 適用於在請求前統一添加一些公共參數,例如在添加 APP 的版本號,用戶 ID ,手機版本號,運營商類型等參數。或者對響應體的數據進行 json 轉化等操做。
5. NetwrokInterceptor 在這一層攔截器中能夠獲取到最終發送請求的 request ,也能夠獲取到真正發生網絡請求回來的 response 響應,從而修改對應的請求或者響應數據。
6. 兩種攔截器的區別
Application interceptors
Don't need to worry about intermediate responses like redirects and retries.
不須要去關心中發生的重定向和重試操做。由於它處於第一個攔截器,會獲取到最終的響應 response 。
Are always invoked once, even if the HTTP response is served from the cache.
只會被調用一次,即便這個響應是從緩存中獲取的。
Observe the application's original intent. Unconcerned with -OkHttp-injected headers like If-None-Match.
只關注最原始的請求,不去關係請求的資源是否發生了改變,我只關注最後的 response 結果而已。
Permitted to short-circuit and not call Chain.proceed().
由於是第一個被執行的攔截器,所以它有權決定了是否要調用其餘攔截,也就是 Chain.proceed() 方法是否要被執行。
Permitted to retry and make multiple calls to Chain.proceed()
由於是第一個被執行的攔截器,所以它有能夠屢次調用 Chain.proceed() 方法,其實也就是至關與從新請求的做用了。
Network Interceptors
Able to operate on intermediate responses like redirects and retries.
由於 NetworkInterceptor 是排在第 6 個攔截器中,所以能夠操做通過 RetryAndFollowup 進行失敗重試或者重定向以後獲得的resposne。
Not invoked for cached responses that short-circuit the network.
對於從緩存獲取的 response 則不會去觸發 NetworkInterceptor 。由於響應直接從 CacheInterceptor 返回了。
Observe the data just as it will be transmitted over the network.
觀察數據在網絡中的傳輸。
Access to the Connection that carries the request.
能夠得到裝載請求的鏈接。
三次握手的實例 : https://www.cnblogs.com/tiwlin/archive/2011/12/25/2301305.html
OkHttp 網址值得去學習 : https://www.jianshu.com/p/ede34ab5b776