OkHttp的简要分析

2019-05-22  本文已影响0人  None_Ling

OkHttp的功能

OkHttp是Android以及Jdk中封装了一套关于网络协议的库。主要实现了网络相关的功能:

OkHttp的使用

OkHttp的使用也非常简单。

// 配置OkHttpClient
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
clientBuilder.addInterceptor(...);
// 生成Post请求的请求参数
FormBody formBody = new FormBody.Builder()
                .add("username", "admin")
                .add("password", "admin")
                .build();
// 生成Http请求实体
final Request request = new Request.Builder()
                .url("http://www.jianshu.com/")
                .post(formBody)
                .build();
Call call = client.build().newCall(request);
// 加入请求队列中
call.enqueue(new Callback=>...);

OkHttp的设计思想

从下图可以看到OkHttp的设计核心思想 - Chain of Responsibility

OkHttp的源码分析

getResponseWithInterceptorChain

RealCall中,通过getResponseWithInterceptorChain会完成以下事情:

而这一切,都在interceptors以及RealInterceptorChain中进行的处理。

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

forWebSocket字段标识当前OkHttpClient是否使用的WebSocket来进行的请求

RealInterceptorChain.proceed

RealInterceptorChain.proceed中,开始按照interceptors的顺序开始责任链处理:

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

interceptors按照顺序开始执行是很重要的,因为有一些变量会在之前的责任链interceptor中被初始化,所以顺序很重要

RetryAndFollowUpInterceptor.intercept

在该函数中,主要完成了:

@Override public Response intercept(Chain chain) throws IOException {
    ...
    // 创建StreamAllocation为ConnectionInterceptor服务
    StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
        createAddress(request.url()), call, eventListener, callStackTrace);
    this.streamAllocation = streamAllocation;

    while (true) {
       ...
      try {
        // 将请求交付后面的Interceptor进行处理,等待结果
        response = realChain.proceed(request, streamAllocation, null, null);
        releaseConnection = false;
      }catch(Exception e){ ... }
      } finally { ... }
      ...
      Request followUp;
      try { 
        // 处理重定向的结果
        followUp = followUpRequest(response, streamAllocation.route());
      } catch (IOException e) {
        streamAllocation.release();
        throw e;
      }
      ...
  }

realChain.proceed之前,都是对Request进行的处理,而在该函数之后,都是对Response进行的处理。即,一个Interceptor里面就包含了Request以及Response的处理。

ConnectInterceptor.intercept

中间还有BridgeInterceptor以及CacheInterceptor就不说了,它们只是对Cookie以及缓存的判断与处理。与真正的链接无关。

这个Interceptor中主要完成:

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

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
    RealConnection connection = streamAllocation.connection();

    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }
StreamAllocation.newStream

该函数主要会完成这几件事:

CallServerInterceptor.intercept

在之前建立完连接后,在这个Interceptor中,会开始发送数据,并且接收Response。

@Override public Response intercept(Chain chain) throws IOException {

    HttpCodec httpCodec = realChain.httpStream();
    Request request = realChain.request();
    ...
    // 通过Codec写请求头
    httpCodec.writeRequestHeaders(request);

    Response.Builder responseBuilder = null;
    // 接收Response头
    responseBuilder = httpCodec.readResponseHeaders(true);

        long contentLength = request.body().contentLength();
        CountingSink requestBodyOut =
            new CountingSink(httpCodec.createRequestBody(request, contentLength));
        BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
      // 写Request的Body
        request.body().writeTo(bufferedRequestBody);
        bufferedRequestBody.close();
     // 写入请求结束符
    httpCodec.finishRequest();

    if (responseBuilder == null) {
      realChain.eventListener().responseHeadersStart(realChain.call());
      responseBuilder = httpCodec.readResponseHeaders(false);
    }

    Response response = responseBuilder
        .request(request)
        .handshake(streamAllocation.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头部数据
      responseBuilder = httpCodec.readResponseHeaders(false);
      response = responseBuilder
              .request(request)
              .handshake(streamAllocation.connection().handshake())
              .sentRequestAtMillis(sentRequestMillis)
              .receivedResponseAtMillis(System.currentTimeMillis())
              .build();
      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 Body
      response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();
    }
    ...
    return response;
  }
上一篇 下一篇

猜你喜欢

热点阅读