美文网首页
Okhttp分析

Okhttp分析

作者: 剩下的只有自己 | 来源:发表于2016-09-19 18:25 被阅读26次

    https://futurestud.io/tutorials/retrofit-getting-started-and-android-client

    class  Request
    {
      private final HttpUrl url;
      private final String method;
      private final Headers headers;
      private final RequestBody body;
      private final Object tag;
    
      private volatile URI javaNetUri; // Lazily initialized.
      private volatile CacheControl cacheControl; // Lazily initialized.
    
      public CacheControl cacheControl() {
        CacheControl result = cacheControl;//这里Request中的cacheControl为null
        return result != null ? result : (cacheControl = CacheControl.parse(headers));//执行cacheControl = CacheControl.parse(headers)
      }
        
    }
    
    class OkHttpClient extends Call.Factory
    {
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      proxySelector = ProxySelector.getDefault();
      cookieJar = CookieJar.NO_COOKIES;
      socketFactory = SocketFactory.getDefault();
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      certificatePinner = CertificatePinner.DEFAULT;
      proxyAuthenticator = Authenticator.NONE;
      authenticator = Authenticator.NONE;
      connectionPool = new ConnectionPool();
      dns = Dns.SYSTEM;
      followSslRedirects = true;
      followRedirects = true;
      retryOnConnectionFailure = true;
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
    
      @Override 
      public Call newCall(Request request) {
        return new RealCall(this, request);
      }
    }
    
    class RealCall extends Call
    {
      private final OkHttpClient client;
    
      // Guarded by this.
      private boolean executed;
      volatile boolean canceled;
    
      /** The application's original request unadulterated by redirects or auth headers. */
      Request originalRequest;
      HttpEngine engine;
    
        @Override 
        public Response execute() throws IOException {
            synchronized (this) {
              if (executed) throw new IllegalStateException("Already Executed");
              executed = true;
            }
            try {
              client.dispatcher().executed(this);
              Response result = getResponseWithInterceptorChain(false);
              if (result == null) throw new IOException("Canceled");
              return result;
            } finally {
              client.dispatcher().finished(this);
            }
        }
    
        private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
            Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
            return chain.proceed(originalRequest);
        }
    
        class ApplicationInterceptorChain
        {
            @Override 
            public Response proceed(Request request) throws IOException {
              // If there's another interceptor in the chain, call that.
              if (index < client.interceptors().size()) {
                Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
                Interceptor interceptor = client.interceptors().get(index);
                Response interceptedResponse = interceptor.intercept(chain);
    
                if (interceptedResponse == null) {
                  throw new NullPointerException("application interceptor " + interceptor
                      + " returned null");
                }
    
                return interceptedResponse;
              }
    
              // No more interceptors. Do HTTP.
              return getResponse(request, forWebSocket);
            }
        }
    
        Response getResponse(Request request, boolean forWebSocket) throws IOException {
            // Copy body metadata to the appropriate request headers.
            RequestBody body = request.body();
            if (body != null) {
              Request.Builder requestBuilder = request.newBuilder();
    
              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");
              }
    
              request = requestBuilder.build();
            }
    
            // Create the initial HTTP engine. Retries and redirects need new engine for each attempt.
            engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);
    
            int followUpCount = 0;
            while (true) {
              if (canceled) {
                engine.releaseStreamAllocation();
                throw new IOException("Canceled");
              }
    
              boolean releaseConnection = true;
              try {
                //**这里开始发送请求**
                engine.sendRequest();
                engine.readResponse();
                releaseConnection = false;
              } catch (RequestException e) {
                // The attempt to interpret the request failed. Give up.
                throw e.getCause();
              } catch (RouteException e) {
                // The attempt to connect via a route failed. The request will not have been sent.
                HttpEngine retryEngine = engine.recover(e.getLastConnectException(), null);
                if (retryEngine != null) {
                  releaseConnection = false;
                  engine = retryEngine;
                  continue;
                }
                // Give up; recovery is not possible.
                throw e.getLastConnectException();
              } catch (IOException e) {
                // An attempt to communicate with a server failed. The request may have been sent.
                HttpEngine retryEngine = engine.recover(e, null);
                if (retryEngine != null) {
                  releaseConnection = false;
                  engine = retryEngine;
                  continue;
                }
    
                // Give up; recovery is not possible.
                throw e;
              } finally {
                // We're throwing an unchecked exception. Release any resources.
                if (releaseConnection) {
                  StreamAllocation streamAllocation = engine.close();
                  streamAllocation.release();
                }
              }
    
              Response response = engine.getResponse();
              Request followUp = engine.followUpRequest();
    
              if (followUp == null) {
                if (!forWebSocket) {
                  engine.releaseStreamAllocation();
                }
                return response;
              }
    
              StreamAllocation streamAllocation = engine.close();
    
              if (++followUpCount > MAX_FOLLOW_UPS) {
                streamAllocation.release();
                throw new ProtocolException("Too many follow-up requests: " + followUpCount);
              }
    
              if (!engine.sameConnection(followUp.url())) {
                streamAllocation.release();
                streamAllocation = null;
              }
    
              request = followUp;
              engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null,
                  response);
            }
      }
    }
    
    class Dispatcher
    {
      /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
      private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
    
      /** Used by {@code Call#execute} to signal it is in-flight. */
      synchronized void executed(RealCall call) {
        runningSyncCalls.add(call);
      }
    }
    
    
    class HttpEngine
    {   
        public final StreamAllocation streamAllocation;
    
        public HttpEngine(OkHttpClient client, Request request, boolean bufferRequestBody,
          boolean callerWritesRequestBody, boolean forWebSocket, StreamAllocation streamAllocation,
          RetryableSink requestBodyOut, Response priorResponse) {
            this.client = client;
            this.userRequest = request;
            this.bufferRequestBody = bufferRequestBody;
            this.callerWritesRequestBody = callerWritesRequestBody;
            this.forWebSocket = forWebSocket;
            this.streamAllocation = streamAllocation != null
                ? streamAllocation
                : new StreamAllocation(client.connectionPool(), createAddress(client, request));
            this.requestBodyOut = requestBodyOut;
            this.priorResponse = priorResponse;
      }
    
      public void sendRequest() throws RequestException, RouteException, IOException {
        if (cacheStrategy != null) return; // Already sent.
        if (httpStream != null) throw new IllegalStateException();
    
        Request request = networkRequest(userRequest);// 1为用户创建的Request添加一些必要的请求头
    
        InternalCache responseCache = Internal.instance.internalCache(client);//这里的Internal对象只在OkhttpClient中被实现,这里返回OkhttpClient中的internalCache为null
        Response cacheCandidate = responseCache != null
            ? responseCache.get(request)
            : null;//responseCache为null,所以这里也为null
    
        long now = System.currentTimeMillis();//当前毫秒
        cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();//没啥操作
        networkRequest = cacheStrategy.networkRequest;//这里为上面的request
        cacheResponse = cacheStrategy.cacheResponse;//null
    
        if (responseCache != null) {//跳过
          responseCache.trackResponse(cacheStrategy);
        }
    
        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) {//跳过
          userResponse = new Response.Builder()
              .request(userRequest)
              .priorResponse(stripBody(priorResponse))
              .protocol(Protocol.HTTP_1_1)
              .code(504)
              .message("Unsatisfiable Request (only-if-cached)")
              .body(EMPTY_BODY)
              .build();
          return;
        }
    
        // If we don't need the network, we're done.
        if (networkRequest == null) {//跳过
          userResponse = cacheResponse.newBuilder()
              .request(userRequest)
              .priorResponse(stripBody(priorResponse))
              .cacheResponse(stripBody(cacheResponse))
              .build();
          userResponse = unzip(userResponse);
          return;
        }
    
        // We need the network to satisfy this request. Possibly for validating a conditional GET.
        boolean success = false;
        try {
          httpStream = connect();
          httpStream.setHttpEngine(this);
    
          if (writeRequestHeadersEagerly()) {
            long contentLength = OkHeaders.contentLength(request);
            if (bufferRequestBody) {
              if (contentLength > Integer.MAX_VALUE) {
                throw new IllegalStateException("Use setFixedLengthStreamingMode() or "
                    + "setChunkedStreamingMode() for requests larger than 2 GiB.");
              }
    
              if (contentLength != -1) {
                // Buffer a request body of a known length.
                httpStream.writeRequestHeaders(networkRequest);
                requestBodyOut = new RetryableSink((int) contentLength);
              } else {
                // Buffer a request body of an unknown length. Don't write request headers until the
                // entire body is ready; otherwise we can't set the Content-Length header correctly.
                requestBodyOut = new RetryableSink();
              }
            } else {
              httpStream.writeRequestHeaders(networkRequest);
              requestBodyOut = httpStream.createRequestBody(networkRequest, contentLength);
            }
          }
          success = true;
        } finally {
          // If we're crashing on I/O or otherwise, don't leak the cache body.
          if (!success && cacheCandidate != null) {
            closeQuietly(cacheCandidate.body());
          }
        }
      }
      
      private HttpStream connect() throws RouteException, RequestException, IOException {
        boolean doExtensiveHealthChecks = !networkRequest.method().equals("GET");//请求是否为!Get方法
        return streamAllocation.newStream(client.connectTimeoutMillis(),
            client.readTimeoutMillis(), client.writeTimeoutMillis(),
            client.retryOnConnectionFailure(), doExtensiveHealthChecks);
      }
    
    
    }
    
    class CahceStrategy
    {   
      /** The request to send on the network, or null if this call doesn't use the network. */
      public final Request networkRequest;
    
      /** The cached response to return or validate; or null if this call doesn't use a cache. */
      public final Response cacheResponse;
    
      private CacheStrategy(Request networkRequest, Response cacheResponse) {
        this.networkRequest = networkRequest;
        this.cacheResponse = cacheResponse;
      }
    
        class Factory
        {
            public Factory(long nowMillis, Request request, Response cacheResponse) {
              this.nowMillis = nowMillis;
              this.request = request;
              this.cacheResponse = cacheResponse;
              ...
            }
            
            public CacheStrategy get() {
              CacheStrategy candidate = getCandidate();
    
              if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {//onlyIfCached()为false,将不会执行里面
                // We're forbidden from using the network and the cache is insufficient.
                return new CacheStrategy(null, null);
              }
    
              return candidate;
           }
           private CacheStrategy getCandidate() {
              // No cached response.
              if (cacheResponse == null) {
                return new CacheStrategy(request, null);
              }
              ...
           }
        }
    }
    
    class CacheControl
    {
        public static CacheControl parse(Headers headers) {
            boolean noCache = false;
            boolean noStore = false;
            int maxAgeSeconds = -1;
            int sMaxAgeSeconds = -1;
            boolean isPrivate = false;
            boolean isPublic = false;
            boolean mustRevalidate = false;
            int maxStaleSeconds = -1;
            int minFreshSeconds = -1;
            boolean onlyIfCached = false;
            boolean noTransform = false;
    
            boolean canUseHeaderValue = true;
            String headerValue = null;
    
            for (int i = 0, size = headers.size(); i < size; i++) {
              String name = headers.name(i);
              String value = headers.value(i);
    
              if (name.equalsIgnoreCase("Cache-Control")) {//heards中没有
                if (headerValue != null) {
                  // Multiple cache-control headers means we can't use the raw value.
                  canUseHeaderValue = false;
                } else {
                  headerValue = value;
                }
              } else if (name.equalsIgnoreCase("Pragma")) {//heards中没有
                // Might specify additional cache-control params. We invalidate just in case.
                canUseHeaderValue = false;
              } else {
                continue;
              }
    
              int pos = 0;
              while (pos < value.length()) {
                int tokenStart = pos;
                pos = HeaderParser.skipUntil(value, pos, "=,;");
                String directive = value.substring(tokenStart, pos).trim();
                String parameter;
    
                if (pos == value.length() || value.charAt(pos) == ',' || value.charAt(pos) == ';') {
                  pos++; // consume ',' or ';' (if necessary)
                  parameter = null;
                } else {
                  pos++; // consume '='
                  pos = HeaderParser.skipWhitespace(value, pos);
    
                  // quoted string
                  if (pos < value.length() && value.charAt(pos) == '\"') {
                    pos++; // consume '"' open quote
                    int parameterStart = pos;
                    pos = HeaderParser.skipUntil(value, pos, "\"");
                    parameter = value.substring(parameterStart, pos);
                    pos++; // consume '"' close quote (if necessary)
    
                    // unquoted string
                  } else {
                    int parameterStart = pos;
                    pos = HeaderParser.skipUntil(value, pos, ",;");
                    parameter = value.substring(parameterStart, pos).trim();
                  }
                }
    
                if ("no-cache".equalsIgnoreCase(directive)) {
                  noCache = true;
                } else if ("no-store".equalsIgnoreCase(directive)) {
                  noStore = true;
                } else if ("max-age".equalsIgnoreCase(directive)) {
                  maxAgeSeconds = HeaderParser.parseSeconds(parameter, -1);
                } else if ("s-maxage".equalsIgnoreCase(directive)) {
                  sMaxAgeSeconds = HeaderParser.parseSeconds(parameter, -1);
                } else if ("private".equalsIgnoreCase(directive)) {
                  isPrivate = true;
                } else if ("public".equalsIgnoreCase(directive)) {
                  isPublic = true;
                } else if ("must-revalidate".equalsIgnoreCase(directive)) {
                  mustRevalidate = true;
                } else if ("max-stale".equalsIgnoreCase(directive)) {
                  maxStaleSeconds = HeaderParser.parseSeconds(parameter, Integer.MAX_VALUE);
                } else if ("min-fresh".equalsIgnoreCase(directive)) {
                  minFreshSeconds = HeaderParser.parseSeconds(parameter, -1);
                } else if ("only-if-cached".equalsIgnoreCase(directive)) {
                  onlyIfCached = true;
                } else if ("no-transform".equalsIgnoreCase(directive)) {
                  noTransform = true;
                }
              }
            }
    
            if (!canUseHeaderValue) {//canUseHeaderValue为true
              headerValue = null;
            }
            return new CacheControl(noCache, noStore, maxAgeSeconds, sMaxAgeSeconds, isPrivate, isPublic,
                mustRevalidate, maxStaleSeconds, minFreshSeconds, onlyIfCached, noTransform, headerValue);//这里的onlyIfCached为false
      }
    }
    
    
    
    

    相关文章

      网友评论

          本文标题:Okhttp分析

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