Okhttp簡介
HTTP是現代應用常用的一種交換數據和媒體的網絡方式,高效地使用HTTP能讓資源加載更快,節省帶寬。OkHttp是一個高效的HTTP客戶端,它有以下默認特性:
- 支持HTTP/2,允許所有同一個主機地址的請求共享同一個socket連接
- 連接池減少請求延時
- 透明的GZIP壓縮減少響應數據的大小
- 緩存響應內容,避免一些完全重復的請求
當網絡出現問題的時候OkHttp依然堅守自己的職責,它會自動恢復一般的連接問題,如果你的服務有多個IP地址,當第一個IP請求失敗時,OkHttp會交替嘗試你配置的其他IP,OkHttp使用現代TLS技術(SNI, ALPN)初始化新的連接,當握手失敗時會回退到TLS 1.0。
pom依賴:
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp --> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.7.2</version> </dependency>
Okhttp使用
本文使用的OkHttp版本為4.7.2。OkHttp的核心類主要有OkHttpClient,Dispatcher,Call,Request,Response,Interceptor,Chain。其中OkHttpClient是負責管理多個Call的組織者,而每個Call又包含一個Request和Response,並且Call中的回調用於提供響應結果。要完成一次網絡請求,我們需要告訴Call需要處理的Request是什么樣的,例如它的URL是什么,然后將Call交給OkHttpClient。OkHttpClient僅對本次請求做一些配置,例如指定緩存路徑,它會讓Dispatcher去決定何時執行Call。而Dispatcher的底層實現就是一個由OkHttp默認實現的線程池,它將最終執行Call中的.run()方法。最后的Interceptor和Chain將用於數據的攔截處理。OkHttp提供兩種方式提交網絡請求,分別是Call.execute()和Call.enqueue(Callback),前者會阻塞線程,后者加入隊列異步執行。通過調用response.body().string()我們可以得到響應的body部分並以String形式返回,但值得注意的是.string()只能調用一次。
創建並配置OkHttpClient
基礎配置
/** * OkHttpClient是通過OkHttpClient.Builder來配置參數的。 */ OkHttpClient.Builder builder = new OkHttpClient.Builder(); //設置連接超時 builder.connectTimeout(30, TimeUnit.SECONDS); //設置讀超時 builder.readTimeout(30, TimeUnit.SECONDS); //設置寫超時 builder.writeTimeout(30, TimeUnit.SECONDS); //是否自動重連 builder.retryOnConnectionFailure(true); //......其他配置 //創建OkHttpClient客戶端,一般一個項目可以將OkHttpClient設置成單例 OkHttpClient okHttpClient = builder.build();
其他配置
//從調用call.execute();和enqueue();這兩個方法開始計時,時間到后網絡還未請求完成將調用cancel();方法 builder.callTimeout(10, TimeUnit.SECONDS); //只有http2和webSocket中有使用,如果設置了這個值會定時的向服務器發送一個消息來保持長連接 builder.pingInterval(10, TimeUnit.SECONDS);
1、添加攔截器
builder.addInterceptor(new LoggingInterceptor());
LoggingInterceptor.java
import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; import java.io.IOException; /** * 請求攔截器 * 打印OKHttp請求日志 */ public class LoggingInterceptor implements Interceptor { @Override public Response intercept(Interceptor.Chain chain) throws IOException { //這個chain里面包含了request和response,所以你要什么都可以從這里拿 Request request = chain.request(); long t1 = System.nanoTime();//請求發起的時間 System.out.println(String.format("發送請求 %s on %s%n%s", request.url(), chain.connection(), request.headers())); Response response = chain.proceed(request); long t2 = System.nanoTime();//收到響應的時間 //這里不能直接使用response.body().string()的方式輸出日志 //因為response.body().string()之后,response中的流會被關閉,程序會報錯,我們需要創建出一 //個新的response給應用層處理 ResponseBody responseBody = response.peekBody(1024 * 1024); System.out.println(String.format("接收響應: [%s] %n返回json:【%s】 %.1fms%n%s", response.request().url(), responseBody.string(), (t2 - t1) / 1e6d, response.headers())); return response; } }
2、
發送請求