美文网首页
OKHttp网络请求原理流程解析

OKHttp网络请求原理流程解析

作者: lizubing1992 | 来源:发表于2019-03-27 12:40 被阅读0次

    1. Okhttp基本使用

    初始化可以添加自定义的拦截器

    OkHttpClient okHttpClient = new OkHttpClient.Builder()
                  .connectTimeout(30, TimeUnit.SECONDS)
                  .writeTimeout(30, TimeUnit.SECONDS)
                  .readTimeout(30, TimeUnit.SECONDS)
                  .addInterceptor(interceptorImpl).builder();//创建OKHttpClient的Builder
    

    基本使用

    String url = "http://wwww.baidu.com";
    final Request request = new Request.Builder()
            .url(url)
            .get()//默认就是GET请求,可以不写
            .build();
    Call call = okHttpClient.newCall(request);
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            Log.d(TAG, "onFailure: ");
        }
    
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            Log.d(TAG, "onResponse: " + response.body().string());
        }
    });
    

    一般的使用大致就是这样的

    2.从OkHttpClient创建开始入手分析

    OkHttpClient.Builder()使用builder模式,用户可以自定义相应的参数

    开发一般会用到的是

      .connectTimeout(30, TimeUnit.SECONDS)
      .writeTimeout(30, TimeUnit.SECONDS)
      .readTimeout(30, TimeUnit.SECONDS)
      .addInterceptor(interceptorImpl)
    

    连接时间,写时间,读时间以及对应的Interceptor相关的拦截器

    3.构建Request

    Request用的也是Builder模式,好处主要是可以动态配置相应的参数

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

    tag主要是做标识的,请求返回为null时候的标识操作

    4.构建Call

    构建Call,主要是调用RealCall.newRealCall方法,并在其内部添加了一个事件回调监听

    /**
       * Prepares the {@code request} to be executed at some point in the future.
       */
      @Override public Call newCall(Request request) {
        return RealCall.newRealCall(this, request, false /* for web socket */);
      }
      
      //RealCall
      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;
      }
      
    

    而在newRealCall方法中同时也调用了RealCall的构造方法
    构造方法中加入了RetryAndFollowUpInterceptor重试拦截器,okhttp中加入了很多拦截器,这也是一大特色

     private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
        this.client = client;
        this.originalRequest = originalRequest;
        this.forWebSocket = forWebSocket;
        this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
      }
    

    5. 执行异步请求enqueue

    @Override public void enqueue(Callback responseCallback) {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
      }
    

    executed以及synchronized主要是用来防止重复操作和多线程同步用的

    接下来的方法

    private void captureCallStackTrace() {
        Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
        retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
      }
    

    重试监听器做一些栈StackTrace记录,以及eventListener.callStart(this);事件监听做回调处理,不影响流程

    接着就到了Dispatcher的enqueue方法

     /** 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<>();
    
     synchronized void enqueue(AsyncCall call) {
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
          runningAsyncCalls.add(call);
          executorService().execute(call);
        } else {
          readyAsyncCalls.add(call);
        }
      }
    

    Dispatcher中定义三个队列分别是readyAsyncCalls异步等待,同步运行runningAsyncCalls以及runningSyncCalls异步运行队列,enqueue方法中,当运行异步队列个数小于最大请求数(64)并且同一Host请求个数小于maxRequestsPerHost(5)则加入异步运行队列,并且用线程执行,否则加入异步等待队列中,这是okhttp的线程队列优化

    6.查看AsyncCall的run方法

    AsyncCall 继承了NamedRunnable,其内部会run方法会调用execute(),代码如下

     @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 {
              eventListener.callFailed(RealCall.this, e);
              responseCallback.onFailure(RealCall.this, e);
            }
          } finally {
            client.dispatcher().finished(this);
          }
        }
      }
    

    signalledCallback这个标识用来处理是否打印对应的日志,这里可以看到Response类,说明网络请求是在getResponseWithInterceptorChain中完成的,之后会回调当前的Call状态值

    7.真正的网络请求的getResponseWithInterceptorChain

    Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.addAll(client.interceptors());
        //失败重试拦截器
        interceptors.add(retryAndFollowUpInterceptor);
        //request和response拦截器
        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);
      }
    

    加入各式各样的拦截器,各个拦截器之间不耦合,易于用户的自己配置,最后调用RealInterceptorChain的proceed方法

    8.RealInterceptorChain的proceed方法

    public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
          HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
          EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
        this.interceptors = interceptors;
        this.connection = connection;
        this.streamAllocation = streamAllocation;
        this.httpCodec = httpCodec;
        this.index = index;
        this.request = request;
        this.call = call;
        this.eventListener = eventListener;
        this.connectTimeout = connectTimeout;
        this.readTimeout = readTimeout;
        this.writeTimeout = writeTimeout;
      }
      
      public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
          RealConnection connection) throws IOException {
        if (index >= interceptors.size()) throw new AssertionError();
    
        calls++;
    
        //...
    
        // Call the next interceptor in the chain.
        RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
            connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
            writeTimeout);
        Interceptor interceptor = interceptors.get(index);
        Response response = interceptor.intercept(next);
    
        // .....
    
        return response;
      }
    

    构造方法中加入了eventListener事件监听,看来okhttp中eventListener的监听一直延伸到这里,还加入了

        this.connectTimeout = connectTimeout;
        this.readTimeout = readTimeout;
        this.writeTimeout = writeTimeout;
    

    连接时间的配置

    要重点关注的是index这个字段,前面传进来的时候,默认是0,而在proceed方法中,又重新执行了RealInterceptorChain的构造方法,并通过 interceptors.get(index)获取下一个拦截器,并且执行interceptor.intercept(next)方法,随便找一个拦截器看看

    public final class BridgeInterceptor implements Interceptor {
    
      @Override public Response intercept(Chain chain) throws IOException {
        //省略部分代码
        Response networkResponse = chain.proceed(requestBuilder.build());
        //省略部分代码
        return responseBuilder.build();
      }
    }
    

    拦截器内部又重新调用了chain.proceed的方法,这和递归操作类似,也是okHttp最经典的责任链模式。

    9.同步操作

     @Override public Response execute() throws IOException {
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        captureCallStackTrace();
        eventListener.callStart(this);
        try {
          client.dispatcher().executed(this);
          Response result = getResponseWithInterceptorChain();
          if (result == null) throw new IOException("Canceled");
          return result;
        } catch (IOException e) {
          eventListener.callFailed(this, e);
          throw e;
        } finally {
          client.dispatcher().finished(this);
        }
      }
    

    同步请求也是通过getResponseWithInterceptorChain来完成的,流程更简单

    10.大致的流程图

    image

    相关文章

      网友评论

          本文标题:OKHttp网络请求原理流程解析

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