okhttp源碼理解

一、介紹
OKHttp是一款高效的HTTP客戶端,支持連接同一地址的鏈接共享同一個socket,通過連接池來減小響應延遲,還有透明的GZIP壓縮,請求緩存等優(yōu)勢,其核心主要有路由、連接協(xié)議、攔截器、代理、安全性認證、連接池以及網(wǎng)絡適配,攔截器主要是指添加,移除或者轉(zhuǎn)換請求或者回應的頭部信息(新版4.x.x是使用kotlin寫的,所以我們這里分析的是3.14.x的版本)
二、使用

       OkHttpClient okHttpClient=new OkHttpClient();
        final Request request=new Request.Builder()
                .url("https://www.wanandroid.com/navi/json")
                .get()
                .build();
        final Call call = okHttpClient.newCall(request);
        try {
            Response response = call.execute();
            Log.e("同步結(jié)果----   ",response.body().string()+"");

        } catch (IOException e) {

            e.printStackTrace();

        }
  1. 構(gòu)造OKHttpClient
  2. 構(gòu)造Request
  3. 得到一個Call
  4. 同步或異步執(zhí)行Call,對應execute()和enqueue方法(線程池最終也是調(diào)用execute())
    這里有個任務分發(fā)器Dispatcher
  private int maxRequests = 64;
  private int maxRequestsPerHost = 5;
  private @Nullable Runnable idleCallback;
 //線程池對象
  private @Nullable ExecutorService executorService;
 //準備執(zhí)行的線程
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
  //正在執(zhí)行的異步線程
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
  //正在執(zhí)行的同步線程
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

這個來用來操作控制任務請求,使用Deque雙端隊列操作

  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    timeout.enter();
    eventListener.callStart(this);
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      e = timeoutExit(e);
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
  }

方法的重點就是返回的Response result = getResponseWithInterceptorChain()

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }

這里是okhttp的精髓Interceptor,使用了責任鏈模式,類似裝飾著模式,層層封裝,給request和Response做不同的處理,View的點擊事件使用的就是責任鏈模式,可以攔截和消費事件。當然我們可以添加自己的Interceptor。

 public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,RealConnection connection) throws IOException {
      //去掉異常處理
    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
  //去掉異常處理
    return response;
  }

Interceptor的順序分別是自定義Interceptor,RetryAndFollowUpInterceptor請求重定向攔截器,重定向攔截器初始化了StreamAllocation對象,這個對象包含請求的一系列參數(shù),每個請求都會有一個StreamAllocation對象,但他們共用Call對象和Address對象,Address包含url,dns,socket和proxy等處理對象,也就是說,RetryAndFollowUpInterceptor中初始化了一系列請求初始化的參數(shù),然后調(diào)用下一個攔截器

BridgeInterceptor
在BridgeInterceptor中拼接了請求頭信息,比如支持gzip格式的參數(shù)
對返回的response做處理

//響應header, 如果沒有自定義配置cookieJar==null,則什么都不做
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
    Response.Builder responseBuilder = networkResponse.newBuilder()
        .request(userRequest);
 //判斷服務器是否支持gzip壓縮格式,如果支持則交給kio壓縮
    if (transparentGzip
        && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
        && HttpHeaders.hasBody(networkResponse)) {
      GzipSource responseBody = new GzipSource(networkResponse.body().source());
      Headers strippedHeaders = networkResponse.headers().newBuilder()
          .removeAll("Content-Encoding")
          .removeAll("Content-Length")
          .build();
      responseBuilder.headers(strippedHeaders);
      String contentType = networkResponse.header("Content-Type");
      responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));

CacheInterceptor
http緩存分為兩種,一種強制緩存,一種對比緩存,強制緩存生效時直接使用以前的請求結(jié)果,無需發(fā)起網(wǎng)絡請求。對比緩存生效時,無論怎樣都會發(fā)起網(wǎng)絡請求,如果請求結(jié)果未改變,服務端會返回304,但不會返回數(shù)據(jù),數(shù)據(jù)從緩存中取,如果改變了會返回數(shù)據(jù)。

//如果緩存和返回都是空的,直接返回504錯誤
if (networkRequest == null && cacheResponse == null) {
      return new Response.Builder()
          .request(chain.request())
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(Util.EMPTY_RESPONSE)
          .sentRequestAtMillis(-1L)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build();
    }

    // 如果強制讀緩存,就去緩存讀取
    if (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }
Response networkResponse = null;
    try {
  //調(diào)用下一個Interceptor
      networkResponse = chain.proceed(networkRequest);
    } finally {
      // 報錯回收資源
      if (networkResponse == null && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }
    if (cacheResponse != null) {
   // 如果返回304,直接調(diào)用緩存數(shù)據(jù)
      if (networkResponse.code() == HTTP_NOT_MODIFIED) {
        Response response = cacheResponse.newBuilder()
            .headers(combine(cacheResponse.headers(), networkResponse.headers()))
            .sentRequestAtMillis(networkResponse.sentRequestAtMillis())
            .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build();
        networkResponse.body().close();

        // Update the cache after combining headers but before stripping the
        // Content-Encoding header (as performed by initContentStream()).
        cache.trackConditionalCacheHit();
        cache.update(cacheResponse, response);
        return response;
      } else {
        closeQuietly(cacheResponse.body());
      }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容