OKHTTP 簡單分析

  

內部使用了OKIO庫, 此庫中Source表示輸入流(至關於InputStream),Sink表示輸出流(至關於OutputStream)php

    特色:java

    ·既支持同步請求,也支持異步請求,同步請求會阻塞當前線程,異步請求不阻塞當前線程,異步執行完成後回掉相應的方法數組

    ·支持HTTP/2協議,經過HTTP/2 可讓客戶端中到服務器的全部請求共用同一個Socket鏈接緩存

    ·非HTTP/2 請求時, OKHTTP內部會維護一個線程池,經過線程池能夠對HTTP/1.x的鏈接進行復用,減小延遲服務器

    ·透明的Gzip處理下降了通訊數據的大小異步

    ·請求的數據能夠進行緩存ide

 

重要的類:post

   ·Request 請求類,OKHTTP中大量使用了Builder構建器模式,Request也不例外,其內部有靜態內部類Builder, 封裝了請求url,請求方法method,請求頭headers, 請求體RequestBody,請求標記tagui

    ·Headers類, 被封裝在Request或Response中,其內部使用一維數組String[] namesAndValues表示header的key value信息,能夠看到除了導入包中的Util、HttpDate類以外,跟OKHTTP的關聯並不大,能夠將此類copy出來單獨分析。在Builder內部類中有一個ArrayList<String> namesAndValuesurl

,當咱們添加header鍵值對時,調用add方法,最終調用addLenient()方法將name,value的值依次添加到列表中,列表內部按照name,value,name2,value2,name3,value3...的順序排列,在build()方法中調用toArray方法再轉換爲String數組,內部元素的順序不變,這樣在用get方法查找的時候

private static String get(String[] namesAndValues, String name) {
    for (int i = namesAndValues.length - 2; i >= 0; i -= 2) {
      if (name.equalsIgnoreCase(namesAndValues[i])) {
        return namesAndValues[i + 1];
      }
    }
    return null;
  }

  

能夠先查找對應的name,獲得name對應的索引後,那麼value是緊隨name其後的,天然能夠獲得value的值。且在查找的時候i的值能夠每隔2作一次處理。這樣有些巧妙的設計,避免使用Map去存儲鍵值對,必定程度上提升了效率。 因爲在調用get方法時是倒序查找,故添加相同的字段時,取最後一個的值。若是使用set(String name, String value) 則會移除舊的name和value。須要注意的是有時候響應頭含有多個重複name的header, 好比有個多 Set-Cookie,這時候能夠調用 values(String name)即可以得到多個值。

    ·ResponseBody 內部使用了OKIO, 能夠獲得字節數組 bytes(), 字符串結果string(),或者是輸入流 byteStream, 特別須要注意的是bytes() string() 方法的註釋,這兩個方法會將響應實體內容所有加載到內存中,因此若是響應實體比較大的話,應該考慮使用流的形式讀取。其中charStream()使用響應頭Content-Type指定的字符集來解析響應體。默認是UTF-8

 

Call

    同步方法execute() 會阻塞當前線程直到有響應。

    異步方法 enqueue(Callback responseCallback)

 

OKHttpClient

    內部也使用Builder構建器模式,能夠配置超時時間,緩存,代理,攔截器等

 

Force a Network Response

    在某些情形下,例如點擊了刷新按鈕以後,有必要跳過緩存,直接向服務器獲取資源,爲了得到刷新後的資源能夠 添加 Connection.addRequestProperty(「Cache-Control」, 「no-cache」), 或者能夠直接使用 connection.addRequestProperty(「Cache-Control」, 「max-age=0」);

Force a Cache Response

    Connection.addRequestProperty(「Cache-Control」, 「only-if-cached」);

 

請求的流程:

    ·異步請求

         建立Request ,執行client.newCall(request).enqueue(Callback)方法,跟蹤newCall方法,方法內部new了一個RealCall,RealCall實現了Call接口,查看RealCall的enqueue方法,最終調用client.dispatcher().enqueue(new AsyncCall(responseCallback);其中Dispatcher內部封裝了線程池(能夠看到默認的線程池也是沒有核心線程, 和Android-Async-http的默認線程池一致),查看Dispatcher的enqueue方法能夠看到若是正在請求的call數量小於最大請求數,則將call添加到runningAsyncCalls中,並提交call到線程池中(AsyncCall實現了Runnable的接口), 查看AsyncCall的構造方法,能夠看到傳入響應的回調,AsyncCall提交到線程池中後,run方法中會調用execute方法,

在AsyncCall的execute方法中經過getResponseWithInterceptorChain()方法獲得Response,並進行響應的請求成功或失敗的回調,而後調用finished方法移除以前添加到Queue中的call。

    

上傳文件:

OkHttpClient httpClient = new OkHttpClient();

RequestBody requestBody = FormBody.create(MediaType.parse("image/jpeg"),
		new File(getExternalCacheDir()+ File.separator +"IMG_20171106_202814.jpg"));

MultipartBody multipartBody = new MultipartBody.Builder()
		.setType(MultipartBody.FORM)
		.addFormDataPart("uploadimg", "IMG_20171106_202814.jpg", requestBody)
		.build();

Request request = new Request.Builder().url("http://www.chuantu.biz/upload.php")
		.addHeader("Cache-Control", "max-age=0")
		.addHeader("Upgrade-Insecure-Requests", "1")
		.addHeader("Accept-Language","zh-CN,zh;q=0.8")
		.post(multipartBody).build();

Call call = httpClient.newCall(request);
call.enqueue(new Callback() {
	@Override
	public void onFailure(Call call, IOException e) {
	}

	@Override
	public void onResponse(Call call, Response response) throws IOException {

		Log.d("song", response.body().string());
	}
});

  

Fidddler抓包的截圖

相關文章
相關標籤/搜索