美文网首页
okhttp3源码分析

okhttp3源码分析

作者: Android_小马范儿 | 来源:发表于2019-06-28 15:14 被阅读0次

    OkHttp3官网

    okhttp3的使用如下:

    1.okhttp3引用--在build.gradle中增加引用

    implementation("com.squareup.okhttp3:okhttp:3.12.0")
    

    2.请求代码如下:

     String url = "https://api.github.com/users/octocat/repos";
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.connectTimeout(20, TimeUnit.SECONDS);
            OkHttpClient okHttpClient = builder.build();
            Request request = new Request.Builder().url(url).build();
            okHttpClient.newCall(request)
                    .enqueue(new Callback() {
                        @Override
                        public void onFailure(Call call, IOException e) {
    
                        }
    
                        @Override
                        public void onResponse(Call call, Response response) throws IOException {
                            System.out.println("OkHTTP===" + response.code());
                        }
                    });
    

    3.执行结果如下:

    OkHTTP===200
    

    4.根据请求代码查看相关内容

    • OkHttpClient.Builder通过构建者模式设置相关参数,相关参数如下
        Dispatcher dispatcher;  //分发器,用来处理网络请求,包括最大请求书,单机最大请求数,线程池
        @Nullable Proxy proxy;//代理
        List<Protocol> protocols;  //Http协议 有HTTP2和HTTP1.1
        List<ConnectionSpec> connectionSpecs; //传输层版本和连接协议,包括TLS版本,无连接的
        final List<Interceptor> interceptors = new ArrayList<>();  //请求拦截器,可以自定义请求数据处理和请求头等相关信息
        final List<Interceptor> networkInterceptors = new ArrayList<>(); //网络拦截器
        EventListener.Factory eventListenerFactory; //事件监听
        ProxySelector proxySelector;//代理选择
        CookieJar cookieJar;//cookie
        @Nullable Cache cache;//缓存
        @Nullable InternalCache internalCache; //内部缓存
        SocketFactory socketFactory; //socket 工厂
        @Nullable SSLSocketFactory sslSocketFactory; //安全套接层socket 工厂,用于HTTPS
        @Nullable CertificateChainCleaner certificateChainCleaner;// 验证确认响应证书 适用 HTTPS 请求连接的主机名
        HostnameVerifier hostnameVerifier;//主机名称确认
        CertificatePinner certificatePinner;//证书链
        Authenticator proxyAuthenticator;//代理身份验证
        Authenticator authenticator;  //本地身份验证
        ConnectionPool connectionPool; //连接池,连接复用
        Dns dns;   //根据域名获取IP地址
        boolean followSslRedirects;  //安全套接层是否重定向
        boolean followRedirects; //重定向
        boolean retryOnConnectionFailure; //重试连接失败
        int callTimeout;  //调用超时 包括整个解析DNS、连接、写入请求体、服务器处理、读取响应体;如果包括重定向或者重试都应该在这个时间内
        int connectTimeout;  //连接超时时间
        int readTimeout; //读超时时间
        int writeTimeout; //写超时时间
        int pingInterval; //web套接字ping间隔
    
    根据Builld参数可以配置的有 复用连接池、增加请求拦截处理请求参数摘要等验证信息处理、连接超时时间、缓存相关内容
    • Request类build配置
      Request(Builder builder) {
        this.url = builder.url;
        this.method = builder.method;
        this.headers = builder.headers.build();
        this.body = builder.body;
        this.tags = Util.immutableMap(builder.tags);
      }
    

    设置url,请求方法,请求头,请求体

    • okHttpClient.newCall(request) 真正的请求处理对象执行enqueue
      @Override public Call newCall(Request request) {
        return RealCall.newRealCall(this, request, false /* for web socket */);
      }
    
    @Override public void enqueue(Callback responseCallback) {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
      }
    

    1.检查这个Call是否执行了,每个Call只能被执行一次
    2.eventListener.callStart,记录请求的步骤
    3.new AsyncCall(responseCallback)异步Call,属于RealCall内部类,执行线程的方法是execute(),所以最后执行的在这个方法
    4、client.dispatcher().enqueue 是OkhttpClient的分发器处理

    • Dispatcher最后的核心代码如下
    private boolean promoteAndExecute() {
        assert (!Thread.holdsLock(this));
    
        List<AsyncCall> executableCalls = new ArrayList<>();
        boolean isRunning;
        synchronized (this) {
          for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
            AsyncCall asyncCall = i.next();
    
            if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
            if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
    
            i.remove();
            executableCalls.add(asyncCall);
            runningAsyncCalls.add(asyncCall);
          }
          isRunning = runningCallsCount() > 0;
        }
    
        for (int i = 0, size = executableCalls.size(); i < size; i++) {
          AsyncCall asyncCall = executableCalls.get(i);
          asyncCall.executeOn(executorService());
        }
    
        return isRunning;
      }
    

    1、两个集合变量readyAsyncCalls、runningAsyncCalls分别代表准备执行的异步Call,已经执行的异步Call集合
    2、maxRequests、maxRequestsPerHost分别代表最大请求数、每个主机最大请求书分别是64、5可设置;executorService()定义的线程池
    2、针对可执行的AsyncCall,遍历执行asyncCall.executeOn(executorService());

    • 最终执行的是AsyncCall的方法,核心代码是getResponseWithInterceptorChain()获取响应值
       /**
         * Attempt to enqueue this async call on {@code executorService}. This will attempt to clean up
         * if the executor has been shut down by reporting the call as failed.
         */
        void executeOn(ExecutorService executorService) {
          assert (!Thread.holdsLock(client.dispatcher()));
          boolean success = false;
          try {
            executorService.execute(this);
            success = true;
          } catch (RejectedExecutionException e) {
            InterruptedIOException ioException = new InterruptedIOException("executor rejected");
            ioException.initCause(e);
            eventListener.callFailed(RealCall.this, ioException);
            responseCallback.onFailure(RealCall.this, ioException);
          } finally {
            if (!success) {
              client.dispatcher().finished(this); // This call is no longer running!
            }
          }
        }
    
        @Override protected void execute() {
          boolean signalledCallback = false;
          timeout.enter();
          try {
            Response response = getResponseWithInterceptorChain();
            if (retryAndFollowUpInterceptor.isCanceled()) {
              signalledCallback = true;
              responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
            } else {
              signalledCallback = true;
              responseCallback.onResponse(RealCall.this, response);
            }
          } catch (IOException e) {
            e = timeoutExit(e);
            if (signalledCallback) {
              // Do not signal the callback twice!
              Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
            } else {
              eventListener.callFailed(RealCall.this, e);
              responseCallback.onFailure(RealCall.this, e);
            }
          } finally {
            client.dispatcher().finished(this);
          }
        }
    

    1、线程池内执行Runnable方法execute()
    2、getResponseWithInterceptorChain()获取响应值

    • 请求的核心就是用责任链的设计模式处理请求体和响应体
    Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.addAll(client.interceptors()); 【1】
        interceptors.add(retryAndFollowUpInterceptor);【2】
        interceptors.add(new BridgeInterceptor(client.cookieJar()));【3】
        interceptors.add(new CacheInterceptor(client.internalCache()));【4】
        interceptors.add(new ConnectInterceptor(client));【5】
        if (!forWebSocket) {
          interceptors.addAll(client.networkInterceptors());【6】
        }
        interceptors.add(new CallServerInterceptor(forWebSocket));【7】
    
        Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
            originalRequest, this, eventListener, client.connectTimeoutMillis(),
            client.readTimeoutMillis(), client.writeTimeoutMillis());
    
        return chain.proceed(originalRequest);
      }
    
    1. client设置的拦截器interceptors
    2. 负责失败重试和重定向的retryAndFollowUpInterceptor
    3. 负责把用户的请求转换为发送服务器的请求,把服务器返回的响应转换为用户友好的响应BridgeInterceptor
    4. 负责读取缓存直接返回、更新缓存的CacheInterceptor
    5. 负责和服务器建立连接的ConnectInterceptor
      6.OkHttpClient 时设置的 networkInterceptors
    6. 负责向服务器发送请求数据、从服务器读取数据的CallServerInterceptor
      8.chain.proceed(originalRequest)开启链式调用

    RealInterceptorChain类开启链式调用

     public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
          RealConnection connection) throws IOException {
        if (index >= interceptors.size()) throw new AssertionError();
    
        calls++;
    
        // If we already have a stream, confirm that the incoming request will use it.
        if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
              + " must retain the same host and port");
        }
    
        // If we already have a stream, confirm that this is the only call to chain.proceed().
        if (this.httpCodec != null && calls > 1) {
          throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
              + " must call proceed() exactly once");
        }
    
        // 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);
    
        // Confirm that the next interceptor made its required call to chain.proceed().
        if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
          throw new IllegalStateException("network interceptor " + interceptor
              + " must call proceed() exactly once");
        }
    
        // Confirm that the intercepted response isn't null.
        if (response == null) {
          throw new NullPointerException("interceptor " + interceptor + " returned null");
        }
    
        if (response.body() == null) {
          throw new IllegalStateException(
              "interceptor " + interceptor + " returned a response with no body");
        }
    
        return response;
      }
    
    • 实例化下一个拦截器,并开启调用,核心代码如下:
       // Call the next interceptor in the chain.  在链式调用上调用下一个拦截器
        RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,connection, index + 1, request, call, eventListener, connectTimeout, readTimeout, writeTimeout);【1】
        Interceptor interceptor = interceptors.get(index); 【2】
        Response response = interceptor.intercept(next);【3】
    
    • 初始化下一个拦截器
    • 获取当前的拦截器
    • 调用当前拦截器的intercept()方法,并将下一个拦截器的RealIterceptorChain对象传递下去;如果Client有增加拦截器interceptors,则第一个执行的就是增加,否则第一个执行的就是retryAndFollowUpInterceptor
    • 责任链里的每个类的核心就是intercept方法,方法内再调用下个拦截器的proceed方法
    RetryAndFollowUpInterceptor负责新建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();
    
        StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
            createAddress(request.url()), call, eventListener, callStackTrace);
        this.streamAllocation = streamAllocation;【1】
    
        int followUpCount = 0;
        Response priorResponse = null;
        while (true) {
          if (canceled) {
            streamAllocation.release();
            throw new IOException("Canceled");
          }
    
          Response response;
          boolean releaseConnection = true;
          try {
            response = realChain.proceed(request, streamAllocation, null, null);【2】
            releaseConnection = false;
          } catch (RouteException e) {
            // The attempt to connect via a route failed. The request will not have been sent.
            if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
              throw e.getFirstConnectException();
            }
            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, streamAllocation, 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;
          try {
            followUp = followUpRequest(response, streamAllocation.route());【3】
          } catch (IOException e) {
            streamAllocation.release();
            throw e;
          }
    
          if (followUp == null) {
            streamAllocation.release();
            return response;
          }
    
          closeQuietly(response.body());
    
          if (++followUpCount > MAX_FOLLOW_UPS) {【4】
            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);
            this.streamAllocation = streamAllocation;
          } 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;
        }
      }
    
    1. 新建StreamAllocation
    2. 调用下一个拦截器;如果发生异常或者未知异常都释放资源
    3. 重定向,如果响应头是300,301,302,303则获取响应头[location]字段,词字段就是重定向的url
    4. 重定向和身份验证最大次数20
    BridgeInterceptor 负责把用户构造的请求转换为发送到服务器的请求、把服务器返回的响应转换为用户友好的响应的
    @Override public Response intercept(Chain chain) throws IOException {
        Request userRequest = chain.request();
        Request.Builder requestBuilder = userRequest.newBuilder();【1】
    
        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) {
          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;
          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());【2】
    
        HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());【3】
    
        Response.Builder responseBuilder = networkResponse.newBuilder()
            .request(userRequest);
    
        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)));
        }
    
        return responseBuilder.build();
      }
    
    1. 新构建一个requestBuilder,添加相关的请求头信息Content-Type、Content-Length、Host、Connection、Accept-Encoding等
    2. 调用下一个责任链
    3. 处理响应相关信息
    CacheInterceptor 用来处理缓存
    @Override public Response intercept(Chain chain) throws IOException {
        Response cacheCandidate = cache != null
            ? cache.get(chain.request())
            : null;
    
        long now = System.currentTimeMillis();
    
        CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
        Request networkRequest = strategy.networkRequest;
        Response cacheResponse = strategy.cacheResponse;【1】
    
        if (cache != null) {
          cache.trackResponse(strategy);
        }
    
        if (cacheCandidate != null && cacheResponse == null) {
          closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
        }
    
        // If we're forbidden from using the network and the cache is insufficient, fail.
        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 we don't need the network, we're done.
        if (networkRequest == null) {
          return cacheResponse.newBuilder()
              .cacheResponse(stripBody(cacheResponse))
              .build();
        }
    
        Response networkResponse = null;
        try {
          networkResponse = chain.proceed(networkRequest);
        } finally {
          // If we're crashing on I/O or otherwise, don't leak the cache body.
          if (networkResponse == null && cacheCandidate != null) {
            closeQuietly(cacheCandidate.body());
          }
        }
    
        // If we have a cache response too, then we're doing a conditional get.
        if (cacheResponse != null) {
          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());
          }
        }
    
        Response response = networkResponse.newBuilder()
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build();
    
        if (cache != null) {
          if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
            // Offer this request to the cache.
            CacheRequest cacheRequest = cache.put(response);
            return cacheWritingResponse(cacheRequest, response);
          }
    
          if (HttpMethod.invalidatesCache(networkRequest.method())) {
            try {
              cache.remove(networkRequest);
            } catch (IOException ignored) {
              // The cache cannot be written.
            }
          }
        }
    
        return response;
      }
    
    1. 根据请求获取缓存,然后把当前时间、请求、缓存构建对象CacheStrategy获取networkRequest、cacheResponse
     public Factory(long nowMillis, Request request, Response cacheResponse) {
          this.nowMillis = nowMillis;
          this.request = request;
          this.cacheResponse = cacheResponse;
    
          if (cacheResponse != null) {
            this.sentRequestMillis = cacheResponse.sentRequestAtMillis();
            this.receivedResponseMillis = cacheResponse.receivedResponseAtMillis();
            Headers headers = cacheResponse.headers();
            for (int i = 0, size = headers.size(); i < size; i++) {
              String fieldName = headers.name(i);
              String value = headers.value(i);
              if ("Date".equalsIgnoreCase(fieldName)) {
                servedDate = HttpDate.parse(value);
                servedDateString = value;
              } else if ("Expires".equalsIgnoreCase(fieldName)) {
                expires = HttpDate.parse(value);
              } else if ("Last-Modified".equalsIgnoreCase(fieldName)) {
                lastModified = HttpDate.parse(value);
                lastModifiedString = value;
              } else if ("ETag".equalsIgnoreCase(fieldName)) {
                etag = value;
              } else if ("Age".equalsIgnoreCase(fieldName)) {
                ageSeconds = HttpHeaders.parseSeconds(value, -1);
              }
            }
          }
        }
    
    • 把缓存的响应体内涉及缓存的响应头信息缓存起来
       public CacheStrategy get() {
          CacheStrategy candidate = getCandidate();
    
          if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {
            // We're forbidden from using the network and the cache is insufficient.
            return new CacheStrategy(null, null);
          }
    
          return candidate;
        }
    
    • 如果getCandidate获取需要新的请求并且请求只能拿缓存数据,则返回的请求和缓存都是null
     private CacheStrategy getCandidate() {
          // No cached response.
          if (cacheResponse == null) {
            return new CacheStrategy(request, null);
          }
    
          // Drop the cached response if it's missing a required handshake.
          if (request.isHttps() && cacheResponse.handshake() == null) {
            return new CacheStrategy(request, null);
          }
    
          // If this response shouldn't have been stored, it should never be used
          // as a response source. This check should be redundant as long as the
          // persistence store is well-behaved and the rules are constant.
          if (!isCacheable(cacheResponse, request)) {
            return new CacheStrategy(request, null);
          }
    
          CacheControl requestCaching = request.cacheControl();
          if (requestCaching.noCache() || hasConditions(request)) {
            return new CacheStrategy(request, null);
          }
    
          CacheControl responseCaching = cacheResponse.cacheControl();
    
          long ageMillis = cacheResponseAge();
          long freshMillis = computeFreshnessLifetime();
    
          if (requestCaching.maxAgeSeconds() != -1) {
            freshMillis = Math.min(freshMillis, SECONDS.toMillis(requestCaching.maxAgeSeconds()));
          }
    
          long minFreshMillis = 0;
          if (requestCaching.minFreshSeconds() != -1) {
            minFreshMillis = SECONDS.toMillis(requestCaching.minFreshSeconds());
          }
    
          long maxStaleMillis = 0;
          if (!responseCaching.mustRevalidate() && requestCaching.maxStaleSeconds() != -1) {
            maxStaleMillis = SECONDS.toMillis(requestCaching.maxStaleSeconds());
          }
    
          if (!responseCaching.noCache() && ageMillis + minFreshMillis < freshMillis + maxStaleMillis) {
            Response.Builder builder = cacheResponse.newBuilder();
            if (ageMillis + minFreshMillis >= freshMillis) {
              builder.addHeader("Warning", "110 HttpURLConnection \"Response is stale\"");
            }
            long oneDayMillis = 24 * 60 * 60 * 1000L;
            if (ageMillis > oneDayMillis && isFreshnessLifetimeHeuristic()) {
              builder.addHeader("Warning", "113 HttpURLConnection \"Heuristic expiration\"");
            }
            return new CacheStrategy(null, builder.build());
          }
    
          // Find a condition to add to the request. If the condition is satisfied, the response body
          // will not be transmitted.
          String conditionName;
          String conditionValue;
          if (etag != null) {
            conditionName = "If-None-Match";
            conditionValue = etag;
          } else if (lastModified != null) {
            conditionName = "If-Modified-Since";
            conditionValue = lastModifiedString;
          } else if (servedDate != null) {
            conditionName = "If-Modified-Since";
            conditionValue = servedDateString;
          } else {
            return new CacheStrategy(request, null); // No condition! Make a regular request.
          }
    
          Headers.Builder conditionalRequestHeaders = request.headers().newBuilder();
          Internal.instance.addLenient(conditionalRequestHeaders, conditionName, conditionValue);
    
          Request conditionalRequest = request.newBuilder()
              .headers(conditionalRequestHeaders.build())
              .build();
          return new CacheStrategy(conditionalRequest, cacheResponse);
        }
    
    1. 缓存本身不存在
    2. 请求是采用https 并且缓存没有进行握手的数据。
    3. 缓存本身不应该不保存下来。可能是缓存本身实现有问题,把一些不应该缓存的数据保留了下来。
    4. 如果请求本身添加了 Cache-Control: No-Cache,或是一些条件请求首部,说明请求不希望使用缓存数据。
    5. 这些情况下直接构造一个包含networkRequest,但是cacheResponse为空的CacheStrategy对象返回
    6. ageMillis + minFreshMillis < freshMillis + maxStaleMillis则直接返回缓存
    7. 如果之前的条件不满足,说明我们的缓存响应已经过期了,这时我们需要通过一个条件请求对服务器进行再验证操作。接下来的代码比较清晰来,就是通过从缓存响应中取出的Last-Modified,Etag,Date首部构造一个条件请求并返回
    接着看CacheInterceptor
    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();
        }
    
    • 如果有缓存但是不可用,且只能缓存则返回504的响应
      if (networkRequest == null) {
          return cacheResponse.newBuilder()
              .cacheResponse(stripBody(cacheResponse))
              .build();
        }
     Response networkResponse = null;
        try {
          networkResponse = chain.proceed(networkRequest);
        } finally {
          // If we're crashing on I/O or otherwise, don't leak the cache body.
          if (networkResponse == null && cacheCandidate != null) {
            closeQuietly(cacheCandidate.body());
          }
        }
    
    • 如果缓存可用,直接返回
      -调用下一个拦截器
    ConnectInterceptor
    Override public Response intercept(Chain chain) throws IOException {
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        Request request = realChain.request();
        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 httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
        RealConnection connection = streamAllocation.connection();
    
        return realChain.proceed(request, streamAllocation, httpCodec, connection);
      }
    
    • 打开一个新的连接到服务端并且调用下一个拦截器
    networkInterceptors

    配置OkHttpClient时设置的 NetworkInterceptors

    CallServerInterceptor 发送和接受数据

    检查请求方法,用Httpcodec处理request
    进行网络请求得到response
    返回response

    总结

    前面根据责任链一个一个的分析,只要责任链中的其中一个返回了respons,则停止向下传递,然后将response向上面的拦截器传递,然后各个拦截器会对respone进行一些处理,最后会传到RealCall类中通过execute来得到esponse

    分析源码一定要看森林,不要看树,否则很容易拖不出来,一定要有方向找到答案就可以,否则分析源码会很困难

    相关文章

      网友评论

          本文标题:okhttp3源码分析

          本文链接:https://www.haomeiwen.com/subject/cwmrcctx.html