Android-OkHttp解析

OkHttp 的依賴

implementation 'com.squareup.okhttp3:okhttp:3.9.0'

OkHttp 的簡單用法

    /**
     * 創(chuàng)建 Call
     */
    private Call newCall() {
        // 創(chuàng)建客戶端對象
        OkHttpClient client = new OkHttpClient.Builder()
                // 設置讀取超時時間
                .readTimeout(5, TimeUnit.SECONDS)
                .build();
        // 創(chuàng)建請求對象
        Request request = new Request.Builder().url("https://www.baidu.com").build();
        // 創(chuàng)建 Call 對象
        Call call = client.newCall(request);
        return call;
    }

    /**
     * 同步請求
     */
    private void synRequest() {
        Call call = newCall();

        new Thread() {
            @Override
            public void run() {
                try {
                    // execute 是 OKHttp 里面的同步請求
                    Response response = call.execute();
                    Log.e("young_test", "synRequest result = " + response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    /**
     * 異步請求
     */
    private void asyRequest (){
        Call call = newCall();
        //  將任務壓入隊列中
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.e("young_test", "asyRequest result = " + response.body().string());
            }
        });
    }

由簡單用法可以知道,OkHttp 的同步請求和異步請求的主要區(qū)別是調(diào)用方法不同赶舆,其他參數(shù)的構(gòu)建是一樣的砌庄。

OkHttp 涉及的設計模式

  • 構(gòu)建者模式(OkHttpClient.Builder封拧、Request.Builder)
  • 責任鏈模式(攔截器 RealInterceptorChain)

一、OkHttp 涉及到的類

  • OkHttpClient:OKHttp 的客戶端類硫狞,設置請求超時時間信轿、讀取超時時間、攔截器残吩、連接池财忽、分發(fā)器、cookie 等泣侮;
    也是 Call即彪、WebSocket 的工廠類;
  • Request:一個HTTP請求活尊。如果類體為null或其本身不可變隶校,該類的實例就是不可變的。主要類配置請求信息(請求 url蛹锰、請求方法深胳、請求頭、請求體等)宁仔;
  • Call:是一個任務接口稠屠,有且只有一個實現(xiàn)類 RealCall峦睡;
  • RealCallCall 的唯一實現(xiàn)類;
  • Dispatcher:分發(fā)器权埠,很核心的一個類榨了,主要用來接收同步/異步的請求隊列,并且持有線程池分發(fā)執(zhí)行任務攘蔽;
  • ConnectionPool:客戶端和服務器的一個連接龙屉,就是一個 Connection,每個Connection 我們都會放到 ConnectionPool 满俗,由 ConnectionPool 進行統(tǒng)一管理連接转捕,當請求的 url 是相同的,則可以選擇復用唆垃;也會制定一些策略五芝,決定哪些復用,哪些需要關(guān)閉辕万;

二枢步、OkHttp 主要執(zhí)行流程

Okhttp主要流程時序圖
OkHttp發(fā)起請求大概流程圖

三、OkHttp 類解析

  1. OkHttpClient
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
    // 分發(fā)器
    final Dispatcher dispatcher;

    // 準備在將來某個時刻執(zhí)行的請求
    @Override
    public Call newCall(Request request) {
        // 調(diào)用 RealCall 的靜態(tài)方法newRealCall創(chuàng)建 RealCall
        return RealCall.newRealCall(this, request, false /* for web socket */);
    }

    // 使用請求連接一個新的網(wǎng)絡套接字(WebSocket)
    @Override
    public WebSocket newWebSocket(Request request, WebSocketListener listener) {
        // 創(chuàng)建 RealWebSocket
        RealWebSocket webSocket = new RealWebSocket(request, listener, new Random());
        // 對 socket 進行連接
        webSocket.connect(this);
        return webSocket;
    }

    // OkHttpClient 的構(gòu)建器
    public static final class Builder {
        // 分發(fā)器
        Dispatcher dispatcher;
        // 連接池
        ConnectionPool connectionPool;

        // 構(gòu)造函數(shù)
        public Builder() {
            // 創(chuàng)建分發(fā)器
            dispatcher = new Dispatcher();
            // 創(chuàng)建連接池
            connectionPool = new ConnectionPool();
        }

        // 構(gòu)造函數(shù)
        Builder(OkHttpClient okHttpClient) {
            // 將 OkHttpClient 中的分發(fā)器渐尿,賦值給 Builder 的 dispatcher
            this.dispatcher = okHttpClient.dispatcher;
            this.connectionPool = okHttpClient.connectionPool;
        }

        // 構(gòu)建OkHttpClient
        public OkHttpClient build() {
            return new OkHttpClient(this);
        }
    }

}
  1. Call (RealCall)
final class RealCall implements Call {
    // 客戶端
    final OkHttpClient client;
    // 重定向和重試攔截器
    final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
    // 守衛(wèi)當前類醉途,保證 execute/enqueue 兩者中的一個只能執(zhí)行一次,也就是保證RealCall只能用一次
    private boolean executed;

    // 構(gòu)造方法私有化
    private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    ...
 this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
    }

    // 用于構(gòu)建 RealCall 對象
    static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    ...
    }

    // 執(zhí)行同步方法
    @Override
    public Response execute() throws IOException {
        synchronized (this) {
            // 用 executed 這個標志砖茸,來保證隘擎,execute/enqueue 只執(zhí)行一次,也就是保證
            // 一個 Call 只可以使用一次
            if (executed) throw new IllegalStateException("Already Executed");
            executed = true;
        }
        // 捕獲調(diào)用堆棧跟蹤
        captureCallStackTrace();
        // 一些網(wǎng)絡回調(diào)操作
        eventListener.callStart(this);
        try {
            // 這句是關(guān)鍵凉夯,將我們需要執(zhí)行的請求(Call)添加到Dispatcher的同步請求隊列中(Dispatcher#runningSyncCalls)
            client.dispatcher().executed(this);
            // 通過責任鏈方式货葬,啟動請求
            Response result = getResponseWithInterceptorChain();
            if (result == null) throw new IOException("Canceled");
            return result;
        } catch (IOException e) {
            eventListener.callFailed(this, e);
            throw e;
        } finally {
            client.dispatcher().finished(this);
        }
    }

    @Override
    public void enqueue(Callback responseCallback) {
        synchronized (this) {
            if (executed) throw new IllegalStateException("Already Executed");
            executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        // 將請求任務添加到 Dispatch 的異步執(zhí)行隊列(Dispatcher#runningAsyncCalls)或 緩存隊列中(Dispatcher#readyAsyncCalls)
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
    }

    // 使用攔截鏈(責任鏈)開啟請求
    Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List<Interceptor> interceptors = new ArrayList<>();
        // 將我們自定義的攔截器加入到攔截器數(shù)組中
        interceptors.addAll(client.interceptors());
        // 重定向和重試攔截器
        interceptors.add(retryAndFollowUpInterceptor);
        // 網(wǎng)絡橋接攔截器
        interceptors.add(new BridgeInterceptor(client.cookieJar()));
        // 緩存攔截器
        interceptors.add(new CacheInterceptor(client.internalCache()));
        // 網(wǎng)絡連接攔截器
        interceptors.add(new ConnectInterceptor(client));
        if (!forWebSocket) {
            // 非網(wǎng)絡套接字(Socket)的時候,可添加客戶端自定義的網(wǎng)絡攔截器
            interceptors.addAll(client.networkInterceptors());
        }
        // 這是鏈中的最后一個攔截器恍涂。它對服務器進行網(wǎng)絡調(diào)用宝惰。
        interceptors.add(new CallServerInterceptor(forWebSocket));

        // 創(chuàng)建攔截器鏈
        Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
                originalRequest, this, eventListener, client.connectTimeoutMillis(),
                client.readTimeoutMillis(), client.writeTimeoutMillis());
        // 調(diào)用 proceed 方法執(zhí)行請求
        return chain.proceed(originalRequest);
    }

    // 異步請求任務
    final class AsyncCall extends NamedRunnable {
        // 異步請求的回調(diào)
        private final Callback responseCallback;

        AsyncCall(Callback responseCallback) {
            // 調(diào)用父類構(gòu)造方法,設置線程名稱
            super("OkHttp %s", redactedUrl());
            this.responseCallback = responseCallback;
        }
    }

    @Override
    protected void execute() {
        // 這個只是表示是否已經(jīng)執(zhí)行了回調(diào)方法
        boolean signalledCallback = false;
        try {
            // 通過責任鏈方式再沧,啟動請求
            Response response = getResponseWithInterceptorChain();
            if (retryAndFollowUpInterceptor.isCanceled()) {
                // 如果重定向攔截器被關(guān)閉尼夺,則表示請求失敗
                // 表示已經(jīng)執(zhí)行了回調(diào)方法
                signalledCallback = true;
                // 回調(diào)失敗方法
                responseCallback.onFailure(okhttp3.RealCall.this, new IOException("Canceled"));
            } else {
                // 表示已經(jīng)執(zhí)行了回調(diào)方法
                signalledCallback = true;
                // 回調(diào)成功方法
                responseCallback.onResponse(okhttp3.RealCall.this, response);
            }
        } catch (IOException e) {
            if (signalledCallback) {
                // Do not signal the callback twice!
                Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
            } else {
                eventListener.callFailed(okhttp3.RealCall.this, e);
                responseCallback.onFailure(okhttp3.RealCall.this, e);
            }
        } finally {
            /*
               下面這句代碼做了幾件事
               1. 將當前任務從執(zhí)行隊列(Dispatcher#runningAsyncCalls/Dispatcher#runningSyncCalls)移除;
               2. 將緩存隊列(Dispatcher#readyAsyncCalls)中的數(shù)據(jù)放到(Dispatcher#runningAsyncCalls)執(zhí)行隊列中(只有異步的時候才執(zhí)行)炒瘸;
               3. 重新計算正在執(zhí)行的任務數(shù)(Dispatcher#runningAsyncCalls.size() + Dispatcher#runningSyncCalls.size())
               4. 如果正在執(zhí)行的任務數(shù)為 0淤堵,同時空閑任務不為空,則執(zhí)行空閑任務
             */

            client.dispatcher().finished(this);
        }
    }

}
  1. Dispatcher
public final class Dispatcher {
    // 最大請求數(shù)
    private int maxRequests = 64;
    // 正在運行的每個主機的請求數(shù)
    private int maxRequestsPerHost = 5;
    // 空閑任務
    private @Nullable
    Runnable idleCallback;

    // 內(nèi)部維護的線程池
    private @Nullable
    ExecutorService executorService;


    // 異步請求任務的緩存隊列
    private final Deque<RealCall.AsyncCall> readyAsyncCalls = new ArrayDeque<>();

    // 正在運行的/已取消運行的異步請求任務隊列
    private final Deque<RealCall.AsyncCall> runningAsyncCalls = new ArrayDeque<>();

    // 正在運行的/已取消的同步請求任務隊列
    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

    // 構(gòu)造函數(shù)
    public Dispatcher(ExecutorService executorService) {
        this.executorService = executorService;
    }

    // 構(gòu)造函數(shù)
    public Dispatcher() {
    }

    // 創(chuàng)建一個線程池
    public synchronized ExecutorService executorService() {
        if (executorService == null) {
            /*
              int corePoolSize:核心線程數(shù)設置為 0顷扩,這樣是為了讓線程快速創(chuàng)建拐邪;
              int maximumPoolSize:最大線程數(shù)設置為最大值,這樣是可以無限制的創(chuàng)建線城池隘截;
              long keepAliveTime:非核心線程的存活時間扎阶,設置 60 秒汹胃;
              TimeUnit unit:非核心線程的存活時間的單位;
              BlockingQueue<Runnable> workQueue:線程執(zhí)行任務的緩存隊列东臀,設置 SynchronousQueue 着饥,是一個空隊列,
              表示不讓線程池里面做任務的緩存操作惰赋,全部由外面的隊列自己維護宰掉;
              ThreadFactory threadFactory:線程池的創(chuàng)建工廠
             */
            // corePoolSize、maximumPoolSize赁濒、workQueue 的設置轨奄,可以讓線程高效的創(chuàng)建和復用,可以更高效率的執(zhí)行任務
            executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
                    new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
        }
        return executorService;
    }

    // 異步請求任務的處理
    synchronized void enqueue(RealCall.AsyncCall call) {
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
            // 如果正在執(zhí)行的異步任務數(shù) < 最大請求任務數(shù)拒炎,同時 正在運行每個主機的請求數(shù) < 最大的正在運行的每個主機的請求數(shù)

            // 將任務添加到正在運行的異步請求隊列
            runningAsyncCalls.add(call);
            // 利用線程池挪拟,執(zhí)行任務
            executorService().execute(call);
        } else {
            // 將任務添加到異步任務緩存隊列中
            readyAsyncCalls.add(call);
        }
    }

    // 同步請求任務的處理
    synchronized void executed(RealCall call) {
        // 將任務添加到同步請求隊列
        runningSyncCalls.add(call);
    }

    // 將異步任務緩存隊列的任務放到正在運行的異步任務隊列中
    private void promoteCalls() {
        // 正在執(zhí)行的的異步任務隊列數(shù)大于最大的異步任務請求數(shù),則直接返回
        if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
        // 異步任務緩存隊列為空击你,則直接返回
        if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

        // 遍歷異步任務緩存隊列
        for (Iterator<RealCall.AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
            RealCall.AsyncCall call = i.next();

            if (runningCallsForHost(call) < maxRequestsPerHost) {
                // 如果正在運行的同主機的請求數(shù) < 最大的每個主機的請求數(shù)
                // 將任務從異步緩存任務隊列中移除
                i.remove();
                // 將任務添加到正在執(zhí)行的異步隊列
                runningAsyncCalls.add(call);
                // 線程池執(zhí)行任務
                executorService().execute(call);
            }
            // 如果正在運行的異步任務隊列 >= 最大的請求數(shù)挥唠,則退出循環(huán)
            if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
        }
    }

    // 返回跟當前執(zhí)行任務的主機相同的正在執(zhí)行的請求數(shù)
    private int runningCallsForHost(RealCall.AsyncCall call) {
        int result = 0;
        // 遍歷正在執(zhí)行的異步請求隊列
        for (RealCall.AsyncCall c : runningAsyncCalls) {
            // 判斷主機是否跟當前任務的主機一樣
            if (c.host().equals(call.host())) result++;
        }
        return result;
    }
}
  1. 攔截器
  • 攔截器核心方法執(zhí)行:proceed -> intercept 愕够,intercept -> proceed
  • 1.創(chuàng)建一系列攔截器踩麦,并將其放入一個攔截器list中虹曙;
  • 2.創(chuàng)建一個攔截器鏈ReallnterceptorChain,并執(zhí)行攔截器鏈的proceed方法谷誓;
  • 3.在發(fā)起請求前對request進行處理绒障;
  • 4.調(diào)用下一個攔截器,獲取response捍歪;
  • 5.對response進行處理户辱,返回給上一個攔截器;

4.1 RetryAndFollowUpInterceptor - 失敗重連攔截器

  • 創(chuàng)建StreamAllocation對象糙臼;
  • 調(diào)用ReallnterceptorChain.proceed(...)進行網(wǎng)絡請求庐镐;
  • 根據(jù)異常結(jié)果或者響應結(jié)果判斷是否要進行重新請求;
  • 調(diào)用下一個攔截器变逃,對response進行處理必逆,返回給上一個攔截器;
public final class RetryAndFollowUpInterceptor implements Interceptor {
    // 最大的允許重定向的次數(shù)揽乱,Chrome是21名眉,F(xiàn)irefox、curl和wget 是 20凰棉,Safari是16损拢,HTTP/1.0推薦5
    private static final int MAX_FOLLOW_UPS = 20;
    // 用來建立和組織http請求所需要的組件的,用來做流分配的
    private StreamAllocation streamAllocation;

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        Call call = realChain.call();
        EventListener eventListener = realChain.eventListener();

        // 創(chuàng)建 StreamAllocation
        streamAllocation = new StreamAllocation(client.connectionPool(), createAddress(request.url()),
                call, eventListener, callStackTrace);

        int followUpCount = 0;
        Response priorResponse = null;
        // 這里之所以用循環(huán)撒犀,是為了防止出現(xiàn)問題的時候福压,跟進結(jié)果判斷是否要進行重新請求
        while (true) {
            if (canceled) {
                streamAllocation.release();
                throw new IOException("Canceled");
            }

            Response response;
            boolean releaseConnection = true;
            try {
                // 調(diào)用攔截鏈的 proceed掏秩,就是調(diào)用下一個攔截器
                response = realChain.proceed(request, streamAllocation, null, null);
                releaseConnection = false;
            } catch (RouteException e) {
                // The attempt to connect via a route failed. The request will not have been sent.
                if (!recover(e.getLastConnectException(), false, request)) {
                    throw e.getLastConnectException();
                }
                releaseConnection = false;
                continue;
            } catch (IOException e) {
                // An attempt to communicate with a server failed. The request may have been sent.
                boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
                if (!recover(e, requestSendStarted, request)) throw e;
                releaseConnection = false;
                continue;
            } finally {
                // We're throwing an unchecked exception. Release any resources.
                if (releaseConnection) {
                    streamAllocation.streamFailed(null);
                    streamAllocation.release();
                }
            }

            // Attach the prior response if it exists. Such responses never have a body.
            if (priorResponse != null) {
                response = response.newBuilder()
                        .priorResponse(priorResponse.newBuilder()
                                .body(null)
                                .build())
                        .build();
            }

            Request followUp = followUpRequest(response);

            if (followUp == null) {
                if (!forWebSocket) {
                    streamAllocation.release();
                }
                return response;
            }

            closeQuietly(response.body());

            if (++followUpCount > MAX_FOLLOW_UPS) {
                streamAllocation.release();
                throw new ProtocolException("Too many follow-up requests: " + followUpCount);
            }

            if (followUp.body() instanceof UnrepeatableRequestBody) {
                streamAllocation.release();
                throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
            }

            if (!sameConnection(response, followUp.url())) {
                streamAllocation.release();
                streamAllocation = new StreamAllocation(client.connectionPool(),
                        createAddress(followUp.url()), call, eventListener, callStackTrace);
            } else if (streamAllocation.codec() != null) {
                throw new IllegalStateException("Closing the body of " + response
                        + " didn't close its backing stream. Bad interceptor?");
            }

            request = followUp;
            priorResponse = response;
        }
    }

}

4.2 BridgeInterceptor- 網(wǎng)絡橋接攔截器

  • 是連接復用的基礎;
  • 是負責將用戶構(gòu)建的一個Request請求轉(zhuǎn)化為能夠進行網(wǎng)絡訪問的請求荆姆;
  • 將這個符合網(wǎng)絡請求的Request進行網(wǎng)絡請求蒙幻;
  • 將網(wǎng)絡請求回來的響應 Response轉(zhuǎn)化為用戶可用的Response;
public final class BridgeInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request userRequest = chain.request();
        Request.Builder requestBuilder = userRequest.newBuilder();

        RequestBody body = userRequest.body();
        if (body != null) {
            MediaType contentType = body.contentType();
            if (contentType != null) {
                requestBuilder.header("Content-Type", contentType.toString());
            }

            long contentLength = body.contentLength();
            if (contentLength != -1) {
                requestBuilder.header("Content-Length", Long.toString(contentLength));
                requestBuilder.removeHeader("Transfer-Encoding");
            } else {
                requestBuilder.header("Transfer-Encoding", "chunked");
                requestBuilder.removeHeader("Content-Length");
            }
        }

        if (userRequest.header("Host") == null) {
            requestBuilder.header("Host", hostHeader(userRequest.url(), false));
        }

        if (userRequest.header("Connection") == null) {
            // 開啟 Keep-Alive胞枕,就是讓 http 開啟后杆煞,一段時間內(nèi)不關(guān)閉
            requestBuilder.header("Connection", "Keep-Alive");
        }

        // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
        // the transfer stream.
        boolean transparentGzip = false;
        if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
            transparentGzip = true;
            // 添加 gzip 壓縮
            requestBuilder.header("Accept-Encoding", "gzip");
        }

        List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
        if (!cookies.isEmpty()) {
            requestBuilder.header("Cookie", cookieHeader(cookies));
        }

        if (userRequest.header("User-Agent") == null) {
            requestBuilder.header("User-Agent", Version.userAgent());
        }

        Response networkResponse = chain.proceed(requestBuilder.build());

        // 將服務器返回的 Response 轉(zhuǎn)換為用戶可以用的 Response
        // 接收響應頭
        HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

        Response.Builder responseBuilder = networkResponse.newBuilder()
                .request(userRequest);

        if (transparentGzip
                && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
                && HttpHeaders.hasBody(networkResponse)) {
            // 客戶端支持 Gzip 壓縮,同時服務器的響應頭是否經(jīng)過 gzip 壓縮腐泻,同時判斷響應頭是否包含 body

            // 將服務器返回的數(shù)據(jù)流轉(zhuǎn)換為解壓的數(shù)據(jù)流
            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");
            // 組織新的 Response
            responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
        }

        return responseBuilder.build();
    }
}

4.3 CacheInterceptor- 緩存攔截器

  • 主要是用 InternalCache 這個類去實現(xiàn)緩存
  • 不是GET方法的請求不會緩存
public final class CacheInterceptor implements Interceptor {
    // 用這個類實現(xiàn)的緩存
    final InternalCache cache;

    public CacheInterceptor(InternalCache cache) {
        this.cache = cache;
    }
}

public final class Cache implements Closeable, Flushable {
    @Nullable
    CacheRequest put(Response response) {
        String requestMethod = response.request().method();
        if (HttpMethod.invalidatesCache(response.request().method())) {
            try {
                this.remove(response.request());
            } catch (IOException var6) {
            }

            return null;
        } else if (!requestMethod.equals("GET")) {
            // 不是GET方法的請求不會緩存
            return null;
        } else if (HttpHeaders.hasVaryAll(response)) {
            return null;
        } else {
            okhttp3.Cache.Entry entry = new okhttp3.Cache.Entry(response);
            DiskLruCache.Editor editor = null;

            try {
                editor = this.cache.edit(key(response.request().url()));
                if (editor == null) {
                    return null;
                } else {
                    entry.writeTo(editor);
                    return new okhttp3.Cache.CacheRequestImpl(editor);
                }
            } catch (IOException var7) {
                this.abortQuietly(editor);
                return null;
            }
        }
    }
}

4.4 ConnectInterceptor- 連接攔截器

打開到目標服務器的連接并繼續(xù)到下一個攔截器决乎;

  • 1.Connectlnterceptor獲取Interceptor傳過來的StreamAllocation,streamAllocation.newStream();
  • ⒉將剛才創(chuàng)建的用于網(wǎng)絡lO的RealConnection對象派桩,以及對于與服務器交互最為關(guān)鍵的HttpCodec等對象傳遞給后面的攔截器构诚;
public final class ConnectInterceptor implements Interceptor {
    public final OkHttpClient client;

    public ConnectInterceptor(OkHttpClient client) {
        this.client = client;
    }

    @Override public Response intercept(Chain chain) throws IOException {
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        Request request = realChain.request();
        // 從上一個攔截器獲取 StreamAllocation
        StreamAllocation streamAllocation = realChain.streamAllocation();

        // We need the network to satisfy this request. Possibly for validating a conditional GET.
        boolean doExtensiveHealthChecks = !request.method().equals("GET");
        // 獲取 HttpCodec ,用來編碼request和解碼response
        HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
        // 獲取 RealConnection铆惑,用來做實際的網(wǎng)絡 IO 傳輸?shù)?        RealConnection connection = streamAllocation.connection();

        // 調(diào)用攔截器鏈的 proceed
        return realChain.proceed(request, streamAllocation, httpCodec, connection);
    }
}

4.5 CallServerInterceptor- 向服務器真正發(fā)起請求攔截器

三范嘱、OkHttp 發(fā)起一次請求的大致流程

1.Call對象對請求的封裝;
2.dispatcher對請求的分發(fā)员魏;
3.getResponseWithlnterceptors()方法丑蛤;
4.RetryAndFollowUplnterceptor
5.Cachelnterceptor
6.Bridgelnterceptor
7.Connectionlnterceptor
8.CallServerlnterceptor


OkHttp自帶攔截器的執(zhí)行順序
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市撕阎,隨后出現(xiàn)的幾起案子受裹,更是在濱河造成了極大的恐慌,老刑警劉巖虏束,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棉饶,死亡現(xiàn)場離奇詭異,居然都是意外死亡镇匀,警方通過查閱死者的電腦和手機照藻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汗侵,“玉大人幸缕,你說我怎么就攤上這事∥希” “怎么了冀值?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宫屠。 經(jīng)常有香客問我列疗,道長,這世上最難降的妖魔是什么浪蹂? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任抵栈,我火速辦了婚禮告材,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘古劲。我一直安慰自己斥赋,他們只是感情好,可當我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布产艾。 她就那樣靜靜地躺著疤剑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪闷堡。 梳的紋絲不亂的頭發(fā)上隘膘,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機與錄音杠览,去河邊找鬼弯菊。 笑死,一個胖子當著我的面吹牛踱阿,可吹牛的內(nèi)容都是我干的管钳。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼软舌,長吁一口氣:“原來是場噩夢啊……” “哼才漆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起佛点,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤栽烂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后恋脚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡焰手,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年糟描,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片书妻。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡船响,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出躲履,到底是詐尸還是另有隱情见间,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布工猜,位于F島的核電站米诉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏篷帅。R本人自食惡果不足惜史侣,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一拴泌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧惊橱,春花似錦蚪腐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至正林,卻和暖如春泡一,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卓囚。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工瘾杭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人哪亿。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓粥烁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蝇棉。 傳聞我的和親對象是個殘疾皇子讨阻,可洞房花燭夜當晚...
    茶點故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容