OKHttp請(qǐng)求流程概述及涉及的設(shè)計(jì)模式

通過(guò)前兩篇文章,大家對(duì)HTTP的許多概念及OkHttp的類結(jié)構(gòu)及使用已經(jīng)有了解,這篇主要講一下OKHttp的整個(gè)請(qǐng)求流程以及這中間涉及到的一些設(shè)計(jì)模式,過(guò)程中會(huì)忽略掉一些局部比較細(xì)節(jié)的問(wèn)題,這些忽略的部分會(huì)在后面的文章中繼續(xù)進(jìn)行深入講解。

發(fā)起請(qǐng)求

我們先看一下OKHttp最外層使用的形式:

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
        .url(url)
        .build();
Call call = client.newCall(request);
//同步請(qǐng)求
Response response = call.execute();

//異步請(qǐng)求
call.enqueue(new Callback() {
      @Override
      public void onFailure(Call call, IOException e) {
        //請(qǐng)求失敗
      }

      @Override
      public void onResponse(Call call, Response response) throws IOException {
        //請(qǐng)求成功
      }
    });

如上代碼既是一般的使用流程,總結(jié)為4步:
1 創(chuàng)建OkHttpClient實(shí)例
2 創(chuàng)建Request實(shí)例
3 用client實(shí)例的newCall方法創(chuàng)建一個(gè)Call實(shí)例
4 調(diào)用Call的同步或異步請(qǐng)求方法,得到Response實(shí)例
對(duì)外部使用來(lái)說(shuō),這就完成了一次請(qǐng)求。
這4步涉及4個(gè)對(duì)象:OkHttpClient、Request、Call、Response。

Requst

首先看Requst對(duì)象,這個(gè)對(duì)象主要攜帶一些我們發(fā)出請(qǐng)求所需的數(shù)據(jù),比如請(qǐng)求地址、請(qǐng)求頭信息等,以下是它所有屬性:

  final HttpUrl url;
  final String method;
  final Headers headers;
  final @Nullable RequestBody body;
  final Object tag;
  private volatile CacheControl cacheControl;

這幾個(gè)屬性都很簡(jiǎn)單:url即我們請(qǐng)求的地址;method即請(qǐng)求方法,默認(rèn)是GET,我們可以設(shè)置成POST等;headers是一些頭信息;body是RequestBody對(duì)象,這個(gè)對(duì)象可以幫我們向服務(wù)端傳送各種格式的數(shù)據(jù),后面會(huì)簡(jiǎn)單介紹一下;tag是這個(gè)Request對(duì)象的標(biāo)記,用來(lái)找到這個(gè)請(qǐng)求對(duì)象,以便在后續(xù)流程中進(jìn)行取消請(qǐng)求等操作;cacheControl用來(lái)控制緩存操作,設(shè)置此次請(qǐng)求是否需要緩存以及緩存時(shí)間等,這里不加詳述,后續(xù)文章中會(huì)有專門針對(duì)緩存的介紹。
再簡(jiǎn)單介紹一下RequestBody對(duì)象,這是一個(gè)抽象類,只有下面3個(gè)方法需要實(shí)現(xiàn):

  public abstract @Nullable MediaType contentType();

  public long contentLength() throws IOException {
    return -1;
  }

  public abstract void writeTo(BufferedSink sink) throws IOException;

這個(gè)類還提供了5個(gè)快速創(chuàng)建實(shí)例的create方法,只需傳入MediaType和相應(yīng)的內(nèi)容數(shù)據(jù)即可創(chuàng)建實(shí)例,如下面代碼:

MediaType JSON = MediaType.parse("application/json; charset=utf-8");
String json = "{name:abc,age:18}";
RequestBody body = RequestBody.create(JSON, json);

OkHttpClient

有了Request里的請(qǐng)求信息,就可以用OkHttpClient創(chuàng)建Call對(duì)象了,OkHttpClient
對(duì)象有很多屬性,這里不再一一列舉,可以理解它就是整個(gè)系統(tǒng)的上下文,收集了請(qǐng)求流程中會(huì)用到的各種數(shù)據(jù),這個(gè)對(duì)象本身也會(huì)在請(qǐng)求發(fā)起時(shí)向下傳遞。這里只關(guān)注一下例子中用到的newCall函數(shù),源碼如下:

@Override public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
  }

可見(jiàn)這個(gè)函數(shù)實(shí)際返回了一共RealCall對(duì)象,一個(gè)Call的子類。RealCall構(gòu)造函數(shù)的第一個(gè)參數(shù)就是OkHttpClient的this,即把這個(gè)對(duì)象向下傳遞了,第二個(gè)參數(shù)是Request,就把請(qǐng)求信息傳遞了下去,第三個(gè)參數(shù)暫時(shí)不用關(guān)心,是關(guān)于web socket的。

Call & RealCall

Call是個(gè)接口,RealCall是它唯一的實(shí)現(xiàn)子類。通過(guò)其構(gòu)造函數(shù)我們知道RealCall里保存了OkHttpClient和Requst,對(duì)于外部調(diào)用來(lái)說(shuō)當(dāng)執(zhí)行execute或enqueue方法時(shí)才真正是網(wǎng)絡(luò)請(qǐng)求的開(kāi)始。
先看execute方法:

  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    try {
      //將這個(gè)請(qǐng)求交給dispatcher管理
      client.dispatcher().executed(this);
      //真正請(qǐng)求開(kāi)始
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }

其中比較關(guān)鍵的是這兩句:
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
第一句將這次請(qǐng)求加入到分發(fā)器的管理之中,分發(fā)器即Dispatcher類,這個(gè)類中有幾個(gè)保存請(qǐng)求的隊(duì)列,我們發(fā)出的每個(gè)請(qǐng)求都會(huì)添加到相應(yīng)的隊(duì)列,我們可以在請(qǐng)求流程中對(duì)每個(gè)請(qǐng)求進(jìn)行狀態(tài)查詢或取消等操作。這個(gè)類就介紹這么多吧,這個(gè)類會(huì)在后續(xù)文章詳細(xì)介紹。
第二句是真正的發(fā)起請(qǐng)求,我們看到調(diào)用了getResponseWithInterceptorChain方法,返回值是Response,說(shuō)明調(diào)用完這個(gè)方法,我們獲得了服務(wù)器發(fā)回的請(qǐng)求結(jié)果。下面詳細(xì)介紹這個(gè)方法。

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);
    return chain.proceed(originalRequest);
  }
}

從源碼看,這個(gè)方法很簡(jiǎn)單,就是在一個(gè)列表里添加一系列的攔截器(xxxInterceptor),然后創(chuàng)建了一個(gè)RealInterceptorChain對(duì)象,并調(diào)用其proceed方法,整個(gè)方法就走完了。但這個(gè)方法在整個(gè)請(qǐng)求流程中是非常重要的,而且這里還涉及一個(gè)責(zé)任鏈模式。
先說(shuō)一下責(zé)任鏈模式,GOF是這樣定義的:

使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接受者之間的耦合關(guān)系。將這個(gè)對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,直到有一個(gè)對(duì)象處理他為止。

2012082915050182.jpg

可以簡(jiǎn)單理解為,當(dāng)有一個(gè)請(qǐng)求需要處理,這時(shí)候有一條處理鏈,鏈上每個(gè)環(huán)都有可能處理這個(gè)請(qǐng)求,但是最終是哪些環(huán)參與了處理,是不一定的,只知道最終這個(gè)請(qǐng)求會(huì)被處理。因?yàn)樽罱K會(huì)被哪些環(huán)節(jié)處理以及順序是怎樣的都不一定,這樣動(dòng)態(tài)性很強(qiáng)。

對(duì)應(yīng)到OkHttp,我們發(fā)出一個(gè)請(qǐng)求,這個(gè)請(qǐng)求也會(huì)經(jīng)歷一系列的處理,上面代碼中添加的每個(gè)攔截器都有可能進(jìn)行處理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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