OkHttp3.9.0 request basic flow

When making a network request using OkHttp, we need to create an instance of OkHttpClient, Call its newCall method to obtain a Call object, and then Call the Call object’s execute or enQueue method to execute the network request synchronously or asynchronously. It looks like this

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
                            .url("url")
                            .build();
Call call = client.newCall(request);
// Synchronize the request
Response response = call.execute();
// Asynchronous request
call.enqueue(new Callback(){
  void onFailure(Call call, IOException e){
    / /...
  }
  void onResponse(Call call, Response response){
    / /...}})Copy the code

As you can see, there are roughly four steps required to initiate a web request using OkHttp

  1. To create aOkHttpClientobject
  2. Create a network requestRequest
  3. callOkHttpClientthenewCallMethod to obtain aCallobject
  4. callCallThe object’sexecuteorenqueueMethod to initiate a network request

createOkHttpClient

OkHttpClient can be created with the new keyword or with the okHttpClient. Builder constructor

public class OkHttpClient implements Cloneable.Call.Factory.WebSocket.Factory {
    final Dispatcher dispatcher;// Policies for executing asynchronous requests.
    final @Nullable Proxy proxy;/ / agent
    final List<Protocol> protocols;// Supported protocols, such as HTTP, http1, http2, and spdy
    final List<ConnectionSpec> connectionSpecs;// Connection specification, used when establishing SSL/TLS connections, contains supported TLS versions and encryption suites, etc
    final List<Interceptor> interceptors;/ / the interceptor
    final List<Interceptor> networkInterceptors;// Network interceptor
    final EventListener.Factory eventListenerFactory;
    final ProxySelector proxySelector;// Proxy selector, which can return proxies based on the URI
    final CookieJar cookieJar;// Provide a cookie persistence policy
    final @Nullable Cache cache;// Response file cache
    final SocketFactory socketFactory;/ / socket factory
    final @Nullable SSLSocketFactory sslSocketFactory;/ / sslSocket factory
    final @Nullable CertificateChainCleaner certificateChainCleaner;// Certificate cleaning tool, used with CertificatePinner
    final HostnameVerifier hostnameVerifier;// Domain name authentication, used to verify whether the requested domain name matches the domain name in the certificate returned by the server
    final CertificatePinner certificatePinner;// Certificate lock, which can be used to set the trust of the specified certificate
    final Authenticator proxyAuthenticator;
    final Authenticator authenticator;
    final ConnectionPool connectionPool;// Connection pool, used to manage the underlying Socket links, link reuse, cleaning, etc
    final Dns dns;
    final boolean followSslRedirects;
    final boolean followRedirects;
    final boolean retryOnConnectionFailure;
    final int connectTimeout;
    final int readTimeout;
    final int writeTimeout;
    final int pingInterval;
}
Copy the code

These fields in OkHttpClient are basically customizable, which shows the power of OkHttp.

createRequest

Request can only be created using Request.Builder. Take a look at some of its fields

public final class Request {
  final HttpUrl url;/ / request URL
  final String method;// Request method
  final Headers headers;// Packet header
  final @Nullable RequestBody body;/ / request body
  final Object tag;

  private volatile CacheControl cacheControl; // Parses the cache-control header and saves the information
}
Copy the code

Request contains all the basic elements of a network Request.

RequestBody

RequestBody is an abstract class that has three methods

public abstract class RequestBody {
  // Corresponds to the content-Type header field
  public abstract @Nullable MediaType contentType(a);
  // Corresponds to the content-Length header field
  public long contentLength(a) throws IOException {
    return -1;
  }
  The sink object is used to write data
  public abstract void writeTo(BufferedSink sink) throws IOException;
}
Copy the code

OkHttp provides several static methods to easily create a RequestBody

public static RequestBody create(MediaType, byte[]);
public static RequestBody create(MediaType, byte[].int.int);
public static RequestBody create(MediaType, ByteString);
public static RequestBody create(MediaType, File);
public static RequestBody create(MediaType, String);
Copy the code

To upload a File, simply call the Create (MediaType, File) method to create a RequestBody, which is then used to create a Request.

newCallcreateCallobject

//OkHttpClient.java
public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
}

//RealCall.java
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
}
Copy the code

NewCall calls RealCall. NewRealCall creates a RealCall object.

Making a Network request

OkHttpClient supports synchronous or asynchronous requests, corresponding to the execute and enQueue methods, respectively.

execute

The result of newCall is a RealCall instance, and let’s look at its execute method

public Response execute(a) throws IOException {
    / /...
    try {
        client.dispatcher().executed(this);
        Response result = getResponseWithInterceptorChain();
        if (result == null) throw new IOException("Canceled");
        return result;
    } catch (IOException e) {
        / /...
        throw e;
    } finally {
        client.dispatcher().finished(this); }}Copy the code

The “executed” and “finished” methods of the Dispatcher are a simple function that involves three method calls

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

The finished method eventually calls the private FINISHED method inside the Dispatcher
/ / calls for runningSyncCalls
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    / /...
    synchronized (this) {
        if(! calls.remove(call))throw new AssertionError("Call wasn't in-flight!");
        / /...
    }
    / /...
}
Copy the code

It can be concluded that the Dispatcher saves the Call object before the network request starts and removes the Call object after the request ends to manage the request.

We take a look at getResponseWithInterceptorChain method, which is the core of OkHttp network request method

Response getResponseWithInterceptorChain(a) throws IOException {
    // Build a full stack of interceptors.
    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));
    if(! forWebSocket) { interceptors.addAll(client.networkInterceptors()); } interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null.null.null.0,
            originalRequest, this, eventListener, client.connectTimeoutMillis(),
            client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
}
Copy the code

Does the keyword interceptor remind you of the chain of responsibility pattern? Yes, the chain of responsibility pattern is used here, so the following interceptors are executed in sequence

  1. The first thing we will do is constructOkHttpClientthroughBuilder.addInterceptorMethod to add interceptors
  2. RetryAndFollowUpInterceptorHandles retries and redirects
  3. BridgeInterceptorResponsible for improving the request header information and decoding the response message body
  4. CacheInterceptorResponsible for cache policy
  5. Execute what we are buildingOkHttpClientthroughBuilder.addNetworkInterceptorMethod to add a network interceptor
  6. ConnectInterceptorResponsible for reuse or creationTCPConnect for subsequent network requests
  7. CallServerInterceptorResponsible for making the actual network request to the server

After the CallServerInterceptor completes execution, the Response object of the request is obtained. This is the general flow of OkHttp when making a network request. The chain of responsibility model is used to accomplish complex and powerful functions in a very elegant way.

enqueue

The process of EnQueue is basically the same as that of Execute. The biggest difference is that enQueue encapsulates network requests into an AsyncCall object and then executes them in a thread pool to initiate asynchronous requests.

public void enqueue(Callback responseCallback) {
    / /...
    //AsyncCall implements the Runnable interface
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
Copy the code
//Dispatcher.java
synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
        runningAsyncCalls.add(call);
        executorService().execute(call);
    } else {
        / /...}}Copy the code

You can see that the dispatcher. enQueue method puts the AsyncCall object into the thread pool for processing.

The execute method fires when AsyncCall is executed

@Override
protected void execute(a) {
    / /...
    try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
            / /...
            responseCallback.onFailure(RealCall.this.new IOException("Canceled"));
        } else {
            / /...
            responseCallback.onResponse(RealCall.this, response); }}catch (IOException e) {
        / /...
        responseCallback.onFailure(RealCall.this, e);

    } finally {
        client.dispatcher().finished(this); }}Copy the code

Is also getResponseWithInterceptorChain mentioned above us is no longer here. The result of the network request is then returned as a callback.

conclusion

OkHttp implements the whole process of network request in interceptor mode, making the whole process of network request simple and clear. To understand OkHttp, you need to delve into the internals of its interceptors, which I’ll look at one by one.