OkHttp 是 Square 公司開源的一款網絡框架,封裝了一個高性能的 http
請求庫。java
okhttp
來進行的okhttp
比較接近真正的 HTTP 協議的框架其餘優勢見:Android 網絡框架比較(後面更新)
提及 okhttp 的介紹,介紹完這幾個關鍵類就能夠了!web
這個類主要是用來配置 okhttp
這個框架的,通俗一點講就是這個類是管理這個框架的各類設置的。json
Call 類的工廠,經過 OkHttpClient 才能獲得 Call 對象。api
OkHttpClient
應該被共享,使用 okhttp
這個框架的時候,最好要將 OkHttpClient
設置成單例模式,全部的 HTTP 在進行請求的時候都要使用這一個 Client
。由於每一個 OkHttpClient
都對應了本身的鏈接池和線程池。減小使用鏈接池和線程池能夠減小延遲和內存的使用。相反的若是每一個請求都建立一個 OkHttpClient
的話會很浪費內存資源。緩存
OkHttpClient 有三個建立方法bash
第一個方法:直接使用 new OkHttpClient()
來建立一個實例對象就能夠了,這個實例對象有默認的配置。默認請求鏈接超時時間 10 s ,讀寫超時時間 10 s,鏈接不成功會自動再次鏈接。服務器
第二個方法:就是經過 Builder
的方式來本身定義一個 OkHttpclient
。固然若是你直接 build
沒有本身配置參數的話,效果和第一個方法是同樣的。websocket
public final OkHttpClient = new OkHttpClient.Builder() .addInterceptor(new HttpLoggingInterceptor()) .cache(new Cache(cacheDir,cacheSize)) .等等配置 .build(); 複製代碼
第三個方法:就是經過已有的 OkHttpClient
對象來複制一份共享線程池和其餘資源的 OkHttpClient
對象。markdown
OkHttpClient agerClient = client.newBuilder() .readTimeout(500,TimeUnit.MILLSECONS) .build(); 複製代碼
這種方法的好處就是,當咱們有一個特殊的請求,有的配置有點不同,好比要求鏈接超過 1 s 就算超時,這個時候咱們就可使用這個方法來生成一個新的實例對象,不過他們共用不少其餘的資源,不會對資源形成浪費。網絡
關於 OkHttpClient 的配置改變都在 Builder 中進行
其實持有的線程池和鏈接池將會被自定釋放若是他們保持閒置的話。
你也能夠自動釋放,釋放後未來再調用 call 的時候會被拒接。
client.dispatcher().excurorService().shutdown()
清除鏈接池,注意清除後,鏈接池的守護線程可能會馬上退出。
client.connectionPool().evictAll()
若是 Client 有緩存,能夠關閉。注意:再次調用一個被關閉的 cache 會發生錯誤。也會形成 crash。
client.cache().close();
OkHttp 在 HTTP/2 鏈接的時候也會使用守護線程。他們閒置的時候將自動退出。
知道有這麼一回事就行,通常不會主動調用。
Call 這個類就是用來發送 HTTP 請求和讀取 HTTP 響應的一個類
這個類的方法不多,從上到下依次是:放棄請求、異步執行請求、同步執行請求。
這個類就是至關於 http
請求中的請求報文,是用來表達請求報文的,因此這裏能夠設置請求的 url、請求頭、請求體等等和請求報文有關的內容。
主要方法羅列:
// 獲取請求 url public HttpUrl url(); // 獲取請求方法類型 public String method(); // 獲取請求頭 public Headers headers(); //獲取請求體 public RequestBody body(); // 獲取 tag public Object tag(); // 返回緩存控制指令,永遠不會是 null ,即便響應不包含 Cache-Control 響應頭 public CacheControl cacheControl(); // 是不是 https 請求 public boolean isHttps(); // Resquest{method=" ",url=" ",tag = " "} public String toString(); 複製代碼
這是它的 Builder
中提供的方法,只設置 .url()
的時候默認是 post 請求。
介紹完請求報文就要介紹請求體了,這都是和 http
協議緊密聯繫的。
RequestBody 就是用來設置請求體的,它的主要方法就是下面這個幾個靜態方法,用來生成對應的請求體:
就是經過這幾個方法來產生對應的不一樣的請求體。MediaType 是用來描述請求體或者響應體類型的。好比請求體類型是 json
串格式的,那對應的 MediaType 就是MediaType.parse("application/json; charset=utf-8");
,若是上傳的是文件那麼對應的就是 application/octet-stream
,還有幾個經常使用的類型 text/plain
imge/png
text/x-markdown
等等。
它還有兩個子類:
FormBody 這個請求體是咱們平時最經常使用的,就是咱們平時使用 post
請求的時候,參數是鍵值對的形式。就是使用這個請求體最簡單了。
說深一點,對應的請求報文是:
POST /test HTTP/1.1 請求行
Host: 32.106.24.148:8080 下面都是請求頭
Content-Type: application/x-www-form-urlencoded 用於指明請求體的類型。
User-Agent: PostmanRuntime/7.15.0
Accept: */*
Cache-Control: no-cache
Postman-Token: 954bda0d-dbc2-4193-addf-a7631cab2cfa,5ba2ebed-90b4-4f35-bcf5-80c4777de471
Host: 39.106.24.148:8080
accept-encoding: gzip, deflate
content-length: 133
Connection: keep-alive
cache-control: no-cache
key0=value0&key1=value1 請求體(也是咱們的參數)
複製代碼
這是發送的原始的報文格式,用代碼實現的話就是
// 建立客戶端 OkHttpClient client = new OkHttpclient(); // 創建請求體 FormBody formBody = new FormBody.Builder() .add("key0", "value0") .add("key1","value1") .build(); // 創建請求報文 Request request = new Request.Builder .post(formBody) .url("請求url") .addHeader("Content-Type", "application/x-www-form-urlencoded") .addHeader("User-Agent", "PostmanRuntime/7.15.0") .addHeader("Accept", "*/*") .addHeader("Cache-Control", "no-cache") .addHeader("Postman-Token", "954bda0d-dbc2-4193-addf-a7631cab2cfa,af7c027c-a7ba-4560-98ae-3a2a473ab88a") .addHeader("Host", "39.106.24.148:8080") .addHeader("accept-encoding", "gzip, deflate") .addHeader("content-length", "133") .addHeader("Connection", "keep-alive") .addHeader("cache-control", "no-cache") .build(); // 發起請求 client.newCall(request).excute(); 複製代碼
上面是使用了 FormBody
的形式,若是使用 RequestBody 的話就要更麻煩一些。
OkHttpClient client = new OkHttpClient(); MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded"); RequestBody body = RequestBody.create(mediaType, "key0=value0&key1=value1"); Request request = new Request.Builder() .url("http://39.106.24.148:8080/test") .post(body) .addHeader("Content-Type", "application/x-www-form-urlencoded") .addHeader("User-Agent", "PostmanRuntime/7.15.0") .addHeader("Accept", "*/*") .addHeader("Cache-Control", "no-cache") .addHeader("Postman-Token", "954bda0d-dbc2-4193-addf-a7631cab2cfa,af7c027c-a7ba-4560-98ae-3a2a473ab88a") .addHeader("Host", "39.106.24.148:8080") .addHeader("accept-encoding", "gzip, deflate") .addHeader("content-length", "133") .addHeader("Connection", "keep-alive") .addHeader("cache-control", "no-cache") .build(); Response response = client.newCall(request).execute(); 複製代碼
固然平時咱們使用的時候,不用拼上這麼多的請求頭,我這樣寫的目的就是爲了更加還原請求報文。
還有一個子類 MultipartBody
這個能夠用來構建比較複雜的請求體。
1995 年 Content-Type 的類型擴充了 multipart/form-data
用來支持向服務器發送二進制數據。若是一次提交多種類型的數據,好比:一張圖片和一個文字,這個時候引入了 boundary
,boundary
使得 POST 能夠知足這種提交多種不一樣的數據類型。經過 boundary
能夠實現多個不一樣類型的數據同時存在在一個 Request 中。兩個 boundary
之間就是一個類型的數據,而且能夠從新設置 Content-Type
與 HTML 文件上傳形式兼容。每塊請求體都是一個請求體,能夠定義本身的請求頭。這些請求頭能夠用來描述這塊請求。例如,他們的 Content-Disposition。若是 Content-Length 和 Content-Type 可用的話,他們會被自動添加到請求頭中。
來看一下這種類型的請求報文是什麼樣的:
POST /web/UploadServlet HTTP/1.1
Content-Type: multipart/form-data; boundary=e1b05ca4-fc4e-4944-837d-cc32c43c853a
Content-Length: 66089
Host: localhost.tt.com:8080
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.5.0
–e1b05ca4-fc4e-4944-837d-cc32c43c853a
Content-Disposition: form-data; name=」file」; filename=」**.png」
Content-Type: image/png
Content-Length: 65744
fdPNG
IHDR�0B7M�iM�M�CCPIM�CC ProfileH��……………………IEND�B`�
–e1b05ca4-fc4e-4944-837d-cc32c43c853a
Content-Disposition: form-data; name=」comment」
Content-Length: 30
上傳一個圖
–e1b05ca4-fc4e-4944-837d-cc32c43c853a–
複製代碼
第一個數據是一張 png 的圖,從新設置了 Content-Type:image/png
中間的亂碼就是圖片的數據。這一堆數據前有一個空行,表示上下分別是請求頭、請求體。
第二個數據,就是一個文本數據。
這樣它們一塊兒構成了請求體。
講起來可能比較複雜,就記住,當既須要上傳參數,又須要上傳文件的時候用這種請求體。
MediaType mediaType = MediaType.parse("image/png"); RequestBody requestBody = new MultipartBody.Builder() // 須要設置成表單形式不然沒法上傳鍵值對參數 .setType(MultipartBody.FORM) .addPart(Headers.of("Content-Disposition", "form-data;name=\"title\""), RequestBody.create(null, "Square Logo")) .addPart( Headers.of("Content-Disposition", "form-data;name=\"imge\""), RequestBody.create(mediaType, new File("路徑/logo.png")) ). build(); Request request = new Request.Builder() .post(requestBody) .url("https://api.imgur.com/3/image") .build(); try { mOkHttpClient.newCall(request).execute(); } catch (IOException e) { e.printStackTrace(); } 複製代碼
簡化寫法:
MediaType mediaType = MediaType.parse("image/png"); RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("title","logo") .addFormDataPart("img","logo.png",RequestBody.create(mediaType,new File("路徑/logo.png"))) .build(); 複製代碼
Content-Disposition 能夠用在消息體的子部分中,用來給出其對應字段的相關信息。做爲 multipart body 中的消息頭,第一個參數老是固定不變的 form-data; 附加的參數不區分大小寫,而且擁有參數值,參數名與參數值用等號鏈接,參數之間用分號分隔。參數值用雙引號括起來
// 好比這樣,就是這種固定的格式 "Content-Disposition","form-data;name=\"mFile\";filename=\"xxx.mp4\"" 複製代碼
到這裏關於請求的幾個重要的類就講完了。
只要掌握 http 請求的原理,使用起 okhttp 來也就不是什麼問題了。
首先 OkHttpClient 是用來設置關於請求工具的一些參數的,好比超時時間、是否緩存等等。
Call 對象是發起 Http 請求的對象,經過 Call 對象來發起請求。
發起請求的時候,須要有請求報文,Request 對象就是對應的請求報文,能夠添加對應的請求行、請求頭、請求體。
提及請求體就是對應了 RequestBody 了。而後這個網絡請求過程就完成了!