神刀安全网

OKHttp源码解析

本文将从类图和一次完整的同步网络请求角度分析OKHttp。如有不妥,欢迎指正。

类图

OKHttp源码解析
Okhttp.png

该类图不是很完整,但是包含了一次请求涉及的类。

GET请求过程

OkHttpClient client = new OkHttpClient();  //1 //新建一个Request对象 Request request = new Request.Builder() //2     .url(url)     .build(); Response response = client.newCall(request).execute(); //3 //获取响应结果 response.body().string(); //4

1.创建OKHttpClient:

final Dispatcher dispatcher;  final Proxy proxy;  final List<Protocol> protocols;  final List<ConnectionSpec> connectionSpecs;  final List<Interceptor> interceptors;  final List<Interceptor> networkInterceptors;  final ProxySelector proxySelector;  final CookieJar cookieJar;  final Cache cache;  final InternalCache internalCache;  final SocketFactory socketFactory;  final SSLSocketFactory sslSocketFactory;  final CertificateChainCleaner certificateChainCleaner;  final HostnameVerifier hostnameVerifier;  final CertificatePinner certificatePinner;  final Authenticator proxyAuthenticator;  final Authenticator authenticator;  final ConnectionPool connectionPool;  final Dns dns;  final boolean followSslRedirects;  final boolean followRedirects;  final boolean retryOnConnectionFailure;  final int connectTimeout;  final int readTimeout;  final int writeTimeout;

OKHttpClient包含了各种配置信息。

2.创建Request

private final HttpUrl url;  //url  private final String method;   //请求方法  private final Headers headers; //首部  private final RequestBody body;  //主题  private final Object tag; //唯一标识一个请求

Request类包含了一次http请求所有的信息。真正执行请求的是这段代码 Response response = client.newCall(request).execute();我们看下OKHttpClient类的newCall()方法:

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

创建并返回了一个RealCall对象。

3.RealCall对象

RealCall实现了Call接口: final class RealCall implements Call  成员变量: final OkHttpClient client; final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor; /** The application's original request unadulterated by redirects or auth headers. */ final Request originalRequest;  //包含请求信息 final boolean forWebSocket; // Guarded by this. private boolean executed;  核心方法:     @Override protected void execute() {       boolean signalledCallback = false;       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) {         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);       }     }   }    Response getResponseWithInterceptorChain() throws IOException {     // Build a full stack of interceptors.     List<Interceptor> interceptors = new ArrayList<>();     interceptors.addAll(client.interceptors());    //添加自定义拦截器     interceptors.add(retryAndFollowUpInterceptor);    //这个拦截器的intercept创建StreamAllocation,回头再看     interceptors.add(new BridgeInterceptor(client.cookieJar()));     interceptors.add(new CacheInterceptor(client.internalCache()));     interceptors.add(new ConnectInterceptor(client));    //这个拦截器的intercept创建HttpCodec,回头再看     if (!forWebSocket) {       interceptors.addAll(client.networkInterceptors());     }     interceptors.add(new CallServerInterceptor(forWebSocket));    //这个拦截器的intercept方法执行网络请求,回头再看      Interceptor.Chain chain = new RealInterceptorChain(         interceptors, null, null, null, 0, originalRequest);    //创建一个RealInterceptorChain对象,传入请求信息和拦截器信息     return chain.proceed(originalRequest);    //开始处理   }

RealCall的execute()中调用了getResponseWithInterceptorChain(),该方法中创建了很多Interceptor,这里使用了职责链模式,几个关键的Intercept已经在注释中标注,回头还会再看。然后创建RealInterceptorChain对象。

4.RealInterceptorChain类:

主要成员变量: private final List<Interceptor> interceptors;   private final StreamAllocation streamAllocation; private final HttpCodec httpCodec;     //执行网络请求 private final Connection connection; private final int index;              //表明当前对象使用的Inteceptor在interceptros列表中的下标 private final Request request;  主要方法:   public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,       Connection 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 && !sameConnection(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);          //创建一个新的RealInterceptorChain对象,该对象的index增加1,表明这个对象由下一个Interceptor处理     Interceptor interceptor = interceptors.get(index);  //获取当前RealInterceptorChain对象的Interceptor     Response response = interceptor.intercept(next); //处理新生成的RealInterceptorChain对象      // 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");     }      return response;   }

proceed()关键的方法已经注释,该方法根据index下标获取一个interceptor,然后生成一个新的RealInterceptorChain对象,作为intercepter.intercept()的参数。我们根据interceptor加入的顺序看看第一个interceptor是谁?

    List<Interceptor> interceptors = new ArrayList<>();     interceptors.addAll(client.interceptors());     interceptors.add(retryAndFollowUpInterceptor);     interceptors.add(new BridgeInterceptor(client.cookieJar()));     interceptors.add(new CacheInterceptor(client.internalCache()));     interceptors.add(new ConnectInterceptor(client));

除了我们自定义的第一个就是retryAndFollowUpInterceptor这个Interceptor。我们看看这个类。

5.RetryAndFollowUpInterceptor类

成员变量: private final OkHttpClient client;  private final boolean forWebSocket;  private StreamAllocation streamAllocation;  private Object callStackTrace;  private volatile boolean canceled;  核心方法:   @Override public Response intercept(Chain chain) throws IOException {     Request request = chain.request();      streamAllocation = new StreamAllocation(         client.connectionPool(), createAddress(request.url()), callStackTrace);  //创建StreamAllocation,这个类和发送字节流有关,后面还会提到      int followUpCount = 0;     Response priorResponse = null;     while (true) {       if (canceled) {         streamAllocation.release();         throw new IOException("Canceled");       }        Response response = null;       boolean releaseConnection = true;       try {         response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);  //又调用chain的proceed方法,该方法又会生成一个RealInterceptorChain对象,交给下一个拦截器处理         releaseConnection = false;       } catch (RouteException e) {         // The attempt to connect via a route failed. The request will not have been sent.         if (!recover(e.getLastConnectException(), true, request)) throw e.getLastConnectException();         releaseConnection = false;         continue;       } catch (IOException e) {         // An attempt to communicate with a server failed. The request may have been sent.         if (!recover(e, false, 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()), 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;     }   }

intercept()方法中重要的地方已经注释,该方法给RealInterceptorChain传入一个生成的StreamAllocation对象,这个对象和发送字节流相关。然后又调用chain的proceed方法,该方法又会生成一个RealInterceptorChain对象,交给下一个拦截器处理。我们看看最后一个拦截器是如何处理RealInterceptorChain的,最后一个拦截器是CallServerInterceptor。

6.CallServerInterceptor 类

@Override public Response intercept(Chain chain) throws IOException {     HttpCodec httpCodec = ((RealInterceptorChain) chain).httpStream();     StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();     Request request = chain.request();      long sentRequestMillis = System.currentTimeMillis();     httpCodec.writeRequestHeaders(request);      if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {       Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);  //这是okio中的类,就是用这个对象发送数据       request.body().writeTo(bufferedRequestBody);   //发送请求实体       bufferedRequestBody.close();     }      httpCodec.finishRequest();      Response response = httpCodec.readResponseHeaders()         .request(request)         .handshake(streamAllocation.connection().handshake())         .sentRequestAtMillis(sentRequestMillis)         .receivedResponseAtMillis(System.currentTimeMillis())         .build();        //接收响应      int code = response.code();     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(httpCodec.openResponseBody(response))           .build();     }      if ("close".equalsIgnoreCase(response.request().header("Connection"))         || "close".equalsIgnoreCase(response.header("Connection"))) {       streamAllocation.noNewStreams();     }      if ((code == 204 || code == 205) && response.body().contentLength() > 0) {       throw new ProtocolException(           "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());     }      return response;   } }

最后一个拦截器真正执行网络请求,关键代码已经注释,将BufferedSink作为RequestBody.writeTo()的参数。我们看看RequestBody是如何用BufferedSink发送数据的。

7.RequestBody

核心方法:   public static RequestBody create(MediaType contentType, String content) {     Charset charset = Util.UTF_8;     if (contentType != null) {       charset = contentType.charset();       if (charset == null) {         charset = Util.UTF_8;         contentType = MediaType.parse(contentType + "; charset=utf-8");       }     }     byte[] bytes = content.getBytes(charset);     return create(contentType, bytes);   }     public static RequestBody create(final MediaType contentType, final byte[] content,       final int offset, final int byteCount) {     if (content == null) throw new NullPointerException("content == null");     Util.checkOffsetAndCount(content.length, offset, byteCount);     return new RequestBody() {       @Override public MediaType contentType() {         return contentType;       }        @Override public long contentLength() {         return byteCount;       }        @Override public void writeTo(BufferedSink sink) throws IOException {         sink.write(content, offset, byteCount);    //调用BufferedSink发送字节流       }     };   }

我们看到RequestBody最终是调用传入的BufferedSink参数将内容的字节发送给服务器。

总结

我们仅仅分析了一次同步请求的过程,还没有分析Okio中的BufferedSink是如何将字节流发送给服务器的,先占个坑。

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » OKHttp源码解析

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址