美文网首页主流框架开源库
主流开源库-OkHttp源码分析

主流开源库-OkHttp源码分析

作者: isLJli | 来源:发表于2020-04-15 08:33 被阅读0次

如对网络知识不熟悉,可跳到最后补一下网络基础
文字总结:
先创建我们的request里面包括我们的Host请求参数等,okhttpClient的.newCall(request)方法生成一个RealCall,RealCall方法是我们的重点,首先执行enqueue方法,RealCall类会调用一个Dispatcher的线程池类,把我们一个异步Call传给Dispatcher线程池,我们Dispatcher类首先判断一下真正执行的任务的数量<64,真在执行host的是否<5,然后把我们的异步Call调用线程池中执行,而异步Call的run()方法最终还是调用RealCall的execute方法,execute方法还是调用的一个得到响应的getResponseWithInterceptorChain(),调用我们的拦截器。


okhttp最基本的请求

添加依赖:
implementation 'com.squareup.okhttp3:okhttp:3.14.5'
//请求客户端
      OkHttpClient okHttpClient = new OkHttpClient();
      //使用builder模式生成request对象
      Request request = new Request.Builder()
              .url("https://i0.hdslb.com/bfs/article/2b2d2f26caa0ebf07dbe617be4a5ba919eaa0724.jpg@1320w_742h.webp")
              .build();
      //请求同步
      Response response = okHttpClient.newCall(request).execute();

      //请求异步,开启一个子线程,不会阻塞
      okHttpClient.newCall(request).enqueue(new Callback() {
          @Override
          public void onFailure(Call call, IOException e) {

          }

          @Override
          public void onResponse(Call call, Response response) throws IOException {

          }
      });

先看看OkHttp最要的类之一RealCall

#RealCall类

//异步的调用方法,参数callBack是个接口实例,最终还是会调用RealCall的execute()方法
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
transmitter.callStart();
client.dispatcher().enqueue(new AsyncCall(responseCallback));//把一个异步Call给线程池请求执行,最终还是调用execute方法
}

#线程池类dispatcher的enqueue
synchronized void enqueue(AsyncCall call) {
 //判断正在执行的数量<64,正在执行请求Host<5
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    runningAsyncCalls.add(call);
    executorService().execute(call); //线程池执行请求,实际回到RealCall.execure()方法
  } else {
    readyAsyncCalls.add(call);
  }
}

//内部异步Call
final class AsyncCall extends NamedRunnable {
  @Override protected void execute() {
    boolean signalledCallback = false;
    transmitter.timeoutEnter();
    try {
      Response response = getResponseWithInterceptorChain();
      signalledCallback = true;
      responseCallback.onResponse(RealCall.this, response);
    } catch (IOException e) {
      if (signalledCallback) {
        // Do not signal the callback twice!
        Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
      } else {
        responseCallback.onFailure(RealCall.this, e);
      }
    } finally {
      client.dispatcher().finished(this);
    }
  }
}
public abstract class NamedRunnable implements Runnable {
......
@Override 
public final void run() {
try {
  execute();//在线程池执行的时候,又回到RealCall.execute方法
} 
protected abstract void execute();
}


//主要作用是调用得到响应的getResponseWithInterceptorChain()方法
@Override public Response execute() throws IOException {
synchronized (this) {
  if (executed) throw new IllegalStateException("Already Executed");
  executed = true;
}
try {
  client.dispatcher().executed(this); //加到同步请求的队列
  return getResponseWithInterceptorChain();//调用拦截器
} finally {
  client.dispatcher().finished(this); //通知dispatcher任务执行完了。
}
}

1.创建客户端okhttpClient源码:

OkHttpClient okHttpClient = new OkHttpClient();

public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
public OkHttpClient() {
     this(new Builder());
}
//Builder.builder()方法调用这个构造函数并把builder传进来
OkHttpClient(Builder builder) {
  this.dispatcher = builder.dispatcher;
  this.proxy = builder.proxy;
  ...
}

public static final class Builder {
public Builder() {
    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;
  }
public OkHttpClient build() {
    return new OkHttpClient(this);
  }
}
}

2.建立Request(http报文)

Request:包括:请求地址url,请求方法method,请求头head,请求数据requestBody,标志位tag

Request request = new Request.Builder().url("url").build();

public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
final @Nullable RequestBody body;
final Map<Class<?>, Object> tags;

private volatile @Nullable CacheControl cacheControl; // Lazily initialized.
//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给我们写
public static class Builder {
  @Nullable HttpUrl url;
  String method;
  Headers.Builder headers;
  @Nullable RequestBody body;

  Map<Class<?>, Object> tags = Collections.emptyMap();

  public Builder() {
   //默认使用get方法
    this.method = "GET";
    this.headers = new Headers.Builder();
  }

  Builder(Request request) {
    this.url = request.url;
    this.method = request.method;
    this.body = request.body;
    this.tags = request.tags.isEmpty()
        ? Collections.emptyMap()
        : new LinkedHashMap<>(request.tags);
    this.headers = request.headers.newBuilder();
  }

//请求头部
public Builder header(String name, String value) {
    headers.set(name, value);
    return this;
  }

public Builder addHeader(String name, String value) {
    headers.add(name, value);
    return this;
  }
public Builder method(String method, RequestBody body) {
    if (method == null) throw new NullPointerException("method == null");
    if (method.length() == 0) throw new IllegalArgumentException("method.length() == 0");
    if (body != null && !HttpMethod.permitsRequestBody(method)) {
      throw new IllegalArgumentException("method " + method + " must not have a request body.");
    }
    if (body == null && HttpMethod.requiresRequestBody(method)) {
      throw new IllegalArgumentException("method " + method + " must have a request body.");
    }
    this.method = method;
    this.body = body;
    return this;
  }

  public Request build() {
    if (url == null) throw new IllegalStateException("url == null");
    return new Request(this);
  }
}

Dispatcher线程池介绍

public final class Dispatcher {
private int maxRequests = 64;
private int maxRequestsPerHost = 5;

/** Executes calls. Created lazily. */
private ExecutorService executorService;

/** Ready async calls in the order they'll be run. */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

public Dispatcher() {
}

public synchronized ExecutorService executorService() {
  if (executorService == null) {
    executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
        new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
  }
  return executorService;
}

synchronized void enqueue(AsyncCall call) {
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    runningAsyncCalls.add(call);
    executorService().execute(call);
  } else {
    readyAsyncCalls.add(call);
  }
}

synchronized void executed(RealCall call) {
  runningSyncCalls.add(call);
}

synchronized void finished(Call call) {
  if (!runningSyncCalls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
}

核心重点拦截器方法得到响应

getResponseWithInterceptorChain():
文字总结拦截器的作用:拦截器可以通过Chain参数拿到上一个的拦截器的request,并通过执行Chain接口的proceed(request)把request传给下一个拦截器并从一个拦截器中拿到response。这是一种责任链的设计模式。

//
public interface Interceptor {
Response intercept(Chain chain) throws IOException;

interface Chain {
  Request request();

  Response proceed(Request request) throws IOException;
  ...
}
}
//实现Interceptor.Chain接口的实例
public final class RealInterceptorChain implements Interceptor.Chain {

@Override public Request request() {
  return request;
}

@Override public Response proceed(Request request) throws IOException {
  return proceed(request, transmitter, exchange);
}

public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
    throws IOException {
        RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange,
      index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
       Interceptor interceptor = interceptors.get(index);
       Response response = interceptor.intercept(next);
       ...
      return response 
}
}

重试拦截器:RetryAndFollowUpInterceptor

文字总结:处理重试的拦截器,会处理一些异常,如果这个异常不是致命的则从返回一个request给下级,如果是致命的则将错误给上级。
再重新生成request时会对状态码进行检查,比如重定向的307,就会从返回的响应中获取新的路径,生成一个新的request给下级重新发起一次请求,如果得到的request为null则返回现在的response给上级。

public final class RetryAndFollowUpInterceptor implements Interceptor {
public RetryAndFollowUpInterceptor(OkHttpClient client) {
  this.client = client;
}

@Override public Response intercept(Chain chain) throws IOException {
  Request request = chain.request();
  RealInterceptorChain realChain = (RealInterceptorChain) chain;
   //一个多路复用
  Transmitter transmitter = realChain.transmitter();

   while (true) {
    transmitter.prepareToConnect(request);

    if (transmitter.isCanceled()) {
      throw new IOException("Canceled");
    }

    Response response;
    boolean success = false;
    try {
      //在try中执行拿到的response
      response = realChain.proceed(request, transmitter, null);
      success = true;
    } catch (RouteException e) {
      //判断是否是致命的异常,如果是则抛出错误给上一级,如果不是则continue下一次请求。
      if (!recover(e.getLastConnectException(), transmitter, false, request)) {
        throw e.getFirstConnectException();
      }
      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, transmitter, requestSendStarted, request)) throw e;
      continue;
    } finally {
      // The network call threw an exception. Release any resources.
      if (!success) {
        transmitter.exchangeDoneDueToException();
      }
    }

    // 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();
    }

    Exchange exchange = Internal.instance.exchange(response);
    Route route = exchange != null ? exchange.connection().route() : null;
   //根据下级返回的response,判断状态码,并重新确定request
    Request followUp = followUpRequest(response, route);

   //如果新的request是null则返回response
    if (followUp == null) {
      if (exchange != null && exchange.isDuplex()) {
        transmitter.timeoutEarlyExit();
      }
      return response;
    }

    RequestBody followUpBody = followUp.body();
    if (followUpBody != null && followUpBody.isOneShot()) {
      return response;
    }

    closeQuietly(response.body());
    if (transmitter.hasExchange()) {
      exchange.detachWithViolence();
    }

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

    request = followUp;
    priorResponse = response;
  }
}

}

桥接拦截器:BridgeInterceptor

文字总结:给请求头部做一些通用的设置,判断返回的response是否用到压缩并把它变成GzipSource,和保存cookie。

public final class BridgeInterceptor implements Interceptor {
private final CookieJar cookieJar;

public BridgeInterceptor(CookieJar cookieJar) {
  this.cookieJar = cookieJar;
}

@Override public Response intercept(Chain chain) throws IOException {
 //得到上一级的request
  Request userRequest = chain.request();
  Request.Builder requestBuilder = userRequest.newBuilder();
  //拿到RequestBody 
  RequestBody body = userRequest.body();
 //根据RequestBody设置一些请求首部的参数
  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
  Response networkResponse = chain.proceed(requestBuilder.build());

  HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

  Response.Builder responseBuilder = networkResponse.newBuilder()
      .request(userRequest);
   //判断是否是gzip压缩,生成GzipSource
  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();
}

/** Returns a 'Cookie' HTTP request header with all cookies, like {@code a=b; c=d}. */
private String cookieHeader(List<Cookie> cookies) {
  StringBuilder cookieHeader = new StringBuilder();
  for (int i = 0, size = cookies.size(); i < size; i++) {
    if (i > 0) {
      cookieHeader.append("; ");
    }
    Cookie cookie = cookies.get(i);
    cookieHeader.append(cookie.name()).append('=').append(cookie.value());
  }
  return cookieHeader.toString();
}
}

缓存拦截器:CacheInterceptor

文字总结:缓存拦截器会根据请求的request和拿到的缓存生成一个缓存策略,缓存策略有需要请求的request和缓存response,根据缓存策略的request和response是否为空进行下一步的操作,比如两个都为null就返回504,request为Null则直接返回本地缓存,根据下级返回的response查看是否状态码是否为304。
在缓存可用的情况下,读取本地的缓存的数据,如果没有直接去服务器,如果有首先判断有没有缓存策略,然后判断有没有过期,如果没有过期直接拿缓存,如果过期了需要添加一些之前头部信息如:If-Modified-Since ,这个时候后台有可能会给你返回 304 代表你还是可以拿本地缓存,每次读取到新的响应后做一次缓存。

public final class CacheInterceptor implements Interceptor {
public CacheInterceptor(@Nullable InternalCache cache) {
  this.cache = cache;
}

@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;

  if (cache != null) {
    cache.trackResponse(strategy);
  }

  if (cacheCandidate != null && cacheResponse == null) {
    closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
  }

  // 如果请求的 networkRequest 是空,缓存的 cacheResponse 是空我就返回 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 we don't need the network, we're done.
  if (networkRequest == null) {
  //不用请求,直接返回缓存response
    return cacheResponse.newBuilder()
        .cacheResponse(stripBody(cacheResponse))
        .build();
  }

  //否则,把networkRequest重新请求一遍
  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());
    }
  }

  // 如果本地的缓存不为空,再次请求得到的response的状态码为304,则复用之前的response给上级
  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();

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;
}
}

连接拦截器:ConnectInterceptor

文字总结:

findHealthyConnection() 找一个连接,首先判断有没有健康的,没有就创建(建立Scoket,握手连接),连接缓存。
封装 HttpCodec 里面封装了 okio 的 Source(输入) 和 Sink (输出),我们通过 HttpCodec 就可以操作 Socket的输入输出,我们就可以像服务器写数据和读取返回数据

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();
  Transmitter transmitter = realChain.transmitter();

  // We need the network to satisfy this request. Possibly for validating a conditional GET.
  boolean doExtensiveHealthChecks = !request.method().equals("GET");
 //建立一个多路复用
  Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks);

  return realChain.proceed(request, transmitter, exchange);
}
}

CallServerInterceptor

文字总结:写数据和读取数据
写头部信息,写body表单信息等等

public final class CallServerInterceptor implements Interceptor {
private final boolean forWebSocket;

public CallServerInterceptor(boolean forWebSocket) {
  this.forWebSocket = forWebSocket;
}

@Override public Response intercept(Chain chain) throws IOException {
  RealInterceptorChain realChain = (RealInterceptorChain) chain;
  Exchange exchange = realChain.exchange();
  Request request = realChain.request();

  long sentRequestMillis = System.currentTimeMillis();

  exchange.writeRequestHeaders(request);

  boolean responseHeadersStarted = false;
  Response.Builder responseBuilder = null;
  if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
    // If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
    // Continue" response before transmitting the request body. If we don't get that, return
    // what we did get (such as a 4xx response) without ever transmitting the request body.
    if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
      exchange.flushRequest();
      responseHeadersStarted = true;
      exchange.responseHeadersStart();
      responseBuilder = exchange.readResponseHeaders(true);
    }

    if (responseBuilder == null) {
      if (request.body().isDuplex()) {
        // Prepare a duplex body so that the application can send a request body later.
        exchange.flushRequest();
        BufferedSink bufferedRequestBody = Okio.buffer(
            exchange.createRequestBody(request, true));
        request.body().writeTo(bufferedRequestBody);
      } else {
        // Write the request body if the "Expect: 100-continue" expectation was met.
        BufferedSink bufferedRequestBody = Okio.buffer(
            exchange.createRequestBody(request, false));
        request.body().writeTo(bufferedRequestBody);
        bufferedRequestBody.close();
      }
    } else {
      exchange.noRequestBody();
      if (!exchange.connection().isMultiplexed()) {
        // If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
        // from being reused. Otherwise we're still obligated to transmit the request body to
        // leave the connection in a consistent state.
        exchange.noNewExchangesOnConnection();
      }
    }
  } else {
    exchange.noRequestBody();
  }

  if (request.body() == null || !request.body().isDuplex()) {
    exchange.finishRequest();
  }

  if (!responseHeadersStarted) {
    exchange.responseHeadersStart();
  }

  if (responseBuilder == null) {
    responseBuilder = exchange.readResponseHeaders(false);
  }

  Response response = responseBuilder
      .request(request)
      .handshake(exchange.connection().handshake())
      .sentRequestAtMillis(sentRequestMillis)
      .receivedResponseAtMillis(System.currentTimeMillis())
      .build();

  int code = response.code();
  if (code == 100) {
    // server sent a 100-continue even though we did not request one.
    // try again to read the actual response
    response = exchange.readResponseHeaders(false)
        .request(request)
        .handshake(exchange.connection().handshake())
        .sentRequestAtMillis(sentRequestMillis)
        .receivedResponseAtMillis(System.currentTimeMillis())
        .build();

    code = response.code();
  }

  exchange.responseHeadersEnd(response);

  if (forWebSocket && code == 101) {
    // Connection is upgrading, but we need to ensure interceptors see a non-null response body.
    response = response.newBuilder()
        .body(Util.EMPTY_RESPONSE)
        .build();
  } else {
    response = response.newBuilder()
        .body(exchange.openResponseBody(response))
        .build();
  }

  if ("close".equalsIgnoreCase(response.request().header("Connection"))
      || "close".equalsIgnoreCase(response.header("Connection"))) {
    exchange.noNewExchangesOnConnection();
  }

  if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
    throw new ProtocolException(
        "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
  }

  return response;
}
}

拦截器总结:首先调用retry拦截它可以在传给下级request得到response的过程中对一些非致命的异常进行再一次的请求,对于下级返回的response对状态码进行判断做再次的请求或者给上一级,对于一些致命异常也是返回给上一级。第二个是BridgeInterceptor拦截器,它会对请求的首部做一些通用的设置,并对返回的response进行是否需要压缩的判断返回gzip和保存response的cookie。第三个是cache缓存拦截,会根据请求拿到本地的缓存,并根据请求和本地缓存拿到生成的缓存策略,根据缓存策略的request和response判断是直接返回缓存,还是继续请求,并根据返回的response判断状态码是否继续返回本地缓存。第四connect连接拦截器主要是与服务器建立TCL的握手连接,这里的连接会使用多路复用,就是没有断开连接之前可以有多个请求共享一个连接,端对端是使用socket连接的。第五:CallServer拦截器主要是读写数据。

getResponseWithInterceptorChain得到最上级的resonse响应。

Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors()); //增加自己定义的拦截器
interceptors.add(new RetryAndFollowUpInterceptor(client));//重试拦截器
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, transmitter, null, 0,
    originalRequest, this, client.connectTimeoutMillis(),
    client.readTimeoutMillis(), client.writeTimeoutMillis());

boolean calledNoMoreExchanges = false;
try {
 //reTry拦截器返回的response
  Response response = chain.proceed(originalRequest);
  if (transmitter.isCanceled()) {
    closeQuietly(response);
    throw new IOException("Canceled");
  }
  return response;
} catch (IOException e) {
  calledNoMoreExchanges = true;
  throw transmitter.noMoreExchanges(e);
} finally {
  if (!calledNoMoreExchanges) {
    transmitter.noMoreExchanges(null);
  }
}
}

RealConnect类

ublic final class RealConnection extends Http2Connection.Listener implements Connection {
private static final String NPE_THROW_WITH_NULL = "throw with null exception";
private static final int MAX_TUNNEL_ATTEMPTS = 21;

public final RealConnectionPool connectionPool;
private final Route route;

// The fields below are initialized by connect() and never reassigned.
//以下字段由connect()初始化,并且从不重新分配。

/** 低级TCP套接字. */
private Socket rawSocket;

private Socket socket;
//通过这个对象握手
private Handshake handshake;
private Protocol protocol; //协议
private Http2Connection http2Connection; //http2.0
private BufferedSource source; //输入流
private BufferedSink sink; //输出流

总结:OkHttp的底层是通过Java的Socket发送HTTP请求与接受响应的(这也好理解,HTTP就是基于TCP协议的),但是OkHttp实现了连接池的概念,即对于同一主机的多个请求,其实可以公用一个Socket连接,而不是每次发送完HTTP请求就关闭底层的Socket,这样就实现了连接池的概念。而OkHttp对Socket的读写操作使用的OkIo库进行了一层封装。

image.png

http的相关知识

HTTP,FTP,DNS,TCP,UDP,IP
OSI七层协议:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
五层:应用层、传输层、网络层、数据链路层、物理层

image.png

TCP的三次握手和四次分手

文字总结:
三次握手之后才开始发送数据
客户端先发一条信息给服务端说能听到吗
服务端就发送一条信息并带ACK给客户端说我能听到,你能听到吗
客户端就发送一条信息给服务端说我能听到

四次挥手:
挂了
好的。挂了
好的


image.png

Http报文

请求报文(Qequest):请求头(首部)+空行+请求数据
响应报文(Response):响应头(首部)+空行+响应数据

Http首部

image.png
image.png
请求首部
Accept:用户代理可处理的媒体类型
Accept-Charset:优先的字符集
Accept-Language:优先的语言(自然语言)
Accept-Encoding:优先的内容编码
If-Modified-Since:比较资源的更新时间
If-Range:资源未更新时发送实体 Byte 的范围请求
Cookie: 设置Cookie

响应首部
Cache-Control:控制缓存的行为
set-Cookie: 设置Cookie
Location:令客户端重定向至指定 URI
Expires:实体主体过期的日期时间
Last-Modified:资源的最后修改日期时间
Status Code: 响应的状态码

cookie:服务端发过来的信息,在客户端保存并再请求的时候发给服务端,cookie有个过期时间
session:在服务端保存客户端的信息,断开链接时则失效
token:服务端给客户端的一个id身份号码。

Http缓存

cache-Control(缓存策略):Public、private、no_cache、max_age、no-store(不缓存)
Expires(缓存的过期策略):指名了缓存数据有效的绝对时间,告诉客户端到了这个时间点(比照客户端时间点)后本地缓存就作废了。
如果缓存过期再去请求服务器时,不一定拿到数据(304)

Http状态码

1xx: Infomational (信息状态码) ,接收的请求正在处理
2xx: Succeed(成功),请求正常处理完毕,如 200,204
3xx: Redirection(重定向),需要进行附加操作,一般是没有响应数据返回的,如 304(Not,modified)307
4xx: Client Error (客户端的错误),服务器无法处理请求,如 404,405
5xx: Server Error (服务端的错误),服务器处理请求出错,如 500,502

Http和Https的区别

https=http+加密验证

http的缺点:
1.数据没有加密传输,可能被监听
2.不验证通信方的身份容易被伪装
3.无法验证报文的完成性可能被篡改

TLS/SSL协议:
加密:对称加密(AES,DES)+非对称加密(RSA,DSA)
证书:建立连接的速度会被拖慢,TCP 8次握手

Http1.0和Http2.0的区别

http2.0:
1.使用二进制传输不是文本
2.可以多路复用
3.报头使用了压缩
4.让服务器可以主动推送到客户端

相关文章

网友评论

    本文标题:主流开源库-OkHttp源码分析

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