OkHttp3.9.0之请求基本流程

OkHttp3.9.0之请求基本流程

我们在使用OkHttp进行网络请求时需要创建一个OkHttpClient实例,然后调用其newCall方法获得一个Call对象,然后调用Call对象的executeenqueue方法就可以同步或异步执行网络请求了。就像下面这样

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
                            .url("url")
                            .build();
Call call = client.newCall(request);
//同步请求
Response response = call.execute();
//异步请求
call.enqueue(new Callback(){
  void onFailure(Call call, IOException e){
    //...
  }
  void onResponse(Call call, Response response){
    //...
  }
})
复制代码

可以看到,使用OkHttp发起网络请求,大致需要4个步骤

  1. 创建一个OkHttpClient对象
  2. 创建一个网络请求的Request
  3. 调用OkHttpClientnewCall方法获得一个Call对象
  4. 调用Call对象的executeenqueue方法来发起网络请求

创建OkHttpClient

OkHttpClient可以使用new关键字创建,也可以使用OkHttpClient.Builder以构造器模式进行创建,具体如何创建就不再举例了,我们主要来看一下OkHttpClient中的一些字段以及其作用

public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
    final Dispatcher dispatcher;//有关执行异步请求的策略。
    final @Nullable Proxy proxy;//代理
    final List<Protocol> protocols;//支持的协议,http、http1、http2、spdy等
    final List<ConnectionSpec> connectionSpecs;//连接规格,当建立SSL/TLS连接时会用到,里面包含支持的TLS版本以及加密套件等
    final List<Interceptor> interceptors;//拦截器
    final List<Interceptor> networkInterceptors;//网络拦截器
    final EventListener.Factory eventListenerFactory;
    final ProxySelector proxySelector;//代理选择器,可以根据URI返回代理
    final CookieJar cookieJar;//提供cookie的持久化策略
    final @Nullable Cache cache;//response文件缓存
    final SocketFactory socketFactory;//socket工厂
    final @Nullable SSLSocketFactory sslSocketFactory;//sslSocket工厂
    final @Nullable CertificateChainCleaner certificateChainCleaner;//证书清理工具,与CertificatePinner配合使用
    final HostnameVerifier hostnameVerifier;//域名验证,用来校验请求域名与服务端返回的证书中的域名是否匹配
    final CertificatePinner certificatePinner;//证书锁定,可以用来设置信任指定的证书
    final Authenticator proxyAuthenticator;
    final Authenticator authenticator;
    final ConnectionPool connectionPool;//连接池,用来管理底层的Socket链接,负责链接复用、清理等工作
    final Dns dns;
    final boolean followSslRedirects;
    final boolean followRedirects;
    final boolean retryOnConnectionFailure;
    final int connectTimeout;
    final int readTimeout;
    final int writeTimeout;
    final int pingInterval;
}
复制代码

OkHttpClient中的这些字段基本上都是可以定制的,由此可见OkHttp功能的强大。

创建Request

Request只能通过Request.Builder来创建,来看一下它的一些字段

public final class Request {
  final HttpUrl url;//请求URL
  final String method;//请求方法
  final Headers headers;//报文头部
  final @Nullable RequestBody body;//请求体
  final Object tag;

  private volatile CacheControl cacheControl; //负责解析Cache-Control头,并保存相关信息
}
复制代码

Request包含了一个网络请求的所有基本要素。

RequestBody

RequestBody是一个抽象类,它有三个方法

public abstract class RequestBody {
  //对应Content-Type头部字段
  public abstract @Nullable MediaType contentType();
  //对应Content-Length头部字段
  public long contentLength() throws IOException {
    return -1;
  }
  //入参是一个sink对象,用来写入数据
  public abstract void writeTo(BufferedSink sink) throws IOException;
}
复制代码

OkHttp提供了多个静态方法用来方便地创建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);
复制代码

想要实现文件上传,只需要调用create(MediaType, File)方法创建RequestBody,然后再用这个RequestBody创建Request,非常方便。

newCall创建Call对象

//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;
}
复制代码

OkHttpClient.newCall调用了RealCall.newRealCall创建了一个RealCall对象。

发起网络请求

OkHttpClient支持发起同步或者异步请求,分别对应executeenqueue方法。

execute

通过newCall创建出来的是一个RealCall实例,我们来看看它的execute方法

public Response execute() 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);
    }
}
复制代码

该函数比较简单,主要涉及三个方法调用,我们先来看看Dispatcherexecutedfinished方法

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

//finished方法最终会调用到Dispatcher内部的私有finished方法
//calls为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!");
        //...
    }
    //...
}
复制代码

可以总结出来,Dispatcher在网络请求开始前保存Call对象,在请求结束后移除Call对象,起到管理请求的作用。

我们再来看看getResponseWithInterceptorChain方法,它是OkHttp网络请求的核心方法

Response getResponseWithInterceptorChain() 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);
}
复制代码

看到关键字interceptor是不是想到了责任链模式?是的,这里确实使用了责任链模式,因此会依次执行以下拦截器

  1. 首先会执行我们在构造OkHttpClient时通过Builder.addInterceptor方法添加的拦截器
  2. RetryAndFollowUpInterceptor用于处理重试以及重定向
  3. BridgeInterceptor负责完善请求头部信息,响应消息体的解码工作
  4. CacheInterceptor负责缓存策略
  5. 执行我们在构造OkHttpClient时通过Builder.addNetworkInterceptor方法添加的网络拦截器
  6. ConnectInterceptor负责复用或者创建TCP连接,供之后的网络请求使用
  7. CallServerInterceptor负责向服务端发起真正的网络请求

CallServerInterceptor执行完毕之后,就会获得请求的Response对象。这就是OkHttp进行网络请求时的大致流程。使用了责任链模式,以非常优雅的方式完成了复杂而强大的功能。

enqueue

enqueue的流程与execute基本一致,最大的区别就是它将网络请求封装成一个AsyncCall对象,然后抛到一个线程池中执行,从而达到发起异步请求的功能。

public void enqueue(Callback responseCallback) {
    //...
    //AsyncCall实现了Runnable接口
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
复制代码
//Dispatcher.java
synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
        runningAsyncCalls.add(call);
        executorService().execute(call);
    } else {
        //...
    }
}
复制代码

可以看到Dispatcher.enqueue方法将AsyncCall对象放入到线程池中等待处理。

AsyncCall被执行时会触发其execute方法

@Override
protected void execute() {
    //...
    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);
    }
}
复制代码

同样是getResponseWithInterceptorChain,上面讲过了我们就不再赘述了。然后就是通过回调的形式返回网络请求的结果。

总结

OkHttp以拦截器模式来实现网络请求的全过程,使得整个网络请求的流程简单、清晰。 想要深入理解OkHttp,必须要深入研究其拦截器的内部实现,后面我将会挨个分析各个拦截器的具体实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值