okhttp源码解析

前言

http请求的功能应该是很简单,只是为了鲁棒性和性能需要写很多的代码,发现okhttp还是挺复杂的,但是我们这里还是要好好的搞定他。

正文

我们从最简单的使用开始

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
        .url(url)
        .build();
Response response = client.newCall(request).execute()) {
      return response.body().string();

OkHttpClient,就是一个客户操作的句柄,肯定是初始化了一大堆的默认参数,看先源码

  public OkHttpClient() {
    this(new Builder());
  }
OkHttpClient(Builder builder) {
}

看到builder,我们就放心了(而不是一个库会有两种风格)。直接new出来,大概就是全部用默认参数,request大概也是那样,我们还是直接看client的操作。
下面我们看真的请求过程。

client.newCall(request).execute()

我们看下 到底是如何创造出一个call的。主要代码如下:

    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    //这个暂时没啥用,是个空的类
    call.eventListener = client.eventListenerFactory().create(call);

其实就是一个client有一个RealCall的类似构造函数的东西,.eventListener是现在是个空,啥也不干。现在回到一个最终极的复杂的问题,RealCallexecute()

 @Override
public Response execute() throws IOException {
    ......
    //这段diamante比较奇怪,暂时没搞懂到底要干嘛,貌似是是为了调用周期。
    client.dispatcher().executed(this);
    Response result = getResponseWithInterceptorChain();
    return result;
    ......
    }

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

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

        return chain.proceed(originalRequest);
    }

看到后半部分才是核心啊,这里搞了一个职责链模式,最后通过这个东东来完成所有请求的内容,这里我们还是要好好的研读一番。RealInterceptorChain这个东西其实是一个用来递归调用的类,我们具体来看他的proceed函数.

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    ......
    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);
    //这里类似一个递归调用,第一个interceptor种有个循环,用来递归调用此函数,返回的时候,是真的response部为空的时候,
    Response response = interceptor.intercept(next);

    return response;
  }

其实我们很容易发现这个东西,就是在new一个自己(当然因为职责链已经开始工作,所以只用后一个index即可),然后传入给第一个职责者即可,我们看下第一个职责者做了什么,是不是又回到这个函数,验证我们这是一个循环的猜想,第一个是RetryAndFollowUpInterceptor

 @Override
    public Response intercept(Chain chain) throws IOException {
        ......
        //这是职责链模式,第一个只是为了处理错误等,所以出现一个循环,其他的任何一个拦截器,出现问题,都应该在这里重新处理。
        while (true) {
            ......
                response = realChain.proceed(request, streamAllocation, null, null);
                }
       ......
    }

这个函数灰常复杂,这里暂时不在详细研究,总之就是又一次递归调用我我们刚才RealInterceptorChain的process方法。那么根据之前,他会调用了第二个职责者。因为这个主要是用来处理异常情况,我们不在详细分析代码。我们直接分析后面真正的网络强求部分的职责。第二个职责者是BridgeInterceptor

/**
 * Bridges from application code to network code. First it builds a network request from a user
 * request. Then it proceeds to call the network. Finally it builds a user response from the network
 * response.
 */

@Override
    public Response intercept(Chain chain) throws IOException {
        Request userRequest = chain.request();
        Request.Builder requestBuilder = userRequest.newBuilder();

        RequestBody body = userRequest.body();
        ......
        初始化请求的host
        if (userRequest.header("Host") == null) {
            requestBuilder.header("Host", hostHeader(userRequest.url(), false));
        }
        //这些都是请求的一些参数,可以暂时无视。
        if (userRequest.header("Connection") == null) {
            requestBuilder.header("Connection", "Keep-Alive");
        }

        // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
        // the transfer stream.
        boolean transparentGzip = false;
        if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
            transparentGzip = true;
            requestBuilder.header("Accept-Encoding", "gzip");
        }
        //Cookie这里已经load,有些内容可以不用请求
        List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
        if (!cookies.isEmpty()) {
            requestBuilder.header("Cookie", cookieHeader(cookies));
        }

        if (userRequest.header("User-Agent") == null) {
            requestBuilder.header("User-Agent", Version.userAgent());
        }

        //chain 已经改变了,这里request 也已经改变了。这里又到了职责链的下一步,用来请求后来者来处理,
        Response networkResponse = chain.proceed(requestBuilder.build());

       
    }

注释比较明确,者是一个桥接用户和网络请求的中间者,主要是生成一些网络请求的内容,我们可以看代码,他确实是初始化一些请求的信息,比如host,Accept-Encoding等变量。这里我们不在详细介绍。我们直接看下一个职责者。这是CacheInterceptor

/** Serves requests from the cache and writes responses to the cache. */


 @Override public Response intercept(Chain chain) throws IOException {
 ......
 //这里其实就是刚才初始化完成的东东。不需要介意。
 Request networkRequest = strategy.networkRequest;
    ......
      networkResponse = chain.proceed(networkRequest);
   ......
  }

注释那么明确,从注释中看到这就是从cache中加载请求内容,和吧加载的内容写入cache.cache这些东东不太是我们关注的焦点,我们暂时先放下吧,直接进入下一个请求部分。

/** Opens a connection to the target server and proceeds to the next interceptor. */


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

这个类的注释也比较明确。打开一个连接,然后交给后面的职责这干活。emm这代码很少,确实非常复杂复杂,不想读,不过大概就是创建一个连接,我们可以看到在StreamLoaction中可以看到

result = new RealConnection(connectionPool, selectedRoute);
......
result.connect(connectTimeout, readTimeout, writeTimeout, pingIntervalMillis,
                connectionRetryEnabled, call, eventListener);

这是一个建立连接的部分。这里我只是写了部分代码,有些不想过分追究,有兴趣的童鞋的可以断点一下,这主要是为了创建一个ssl安全验证的socket,这里实在懒得过分追问,反正就是获取一个socket的stream我们继续看我们的真的请求的部分。
最后是一个CallServerInterceptor

/** This is the last interceptor in the chain. It makes a network call to the server. */


    public Response intercept(Chain chain) throws IOException {
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        HttpCodec httpCodec = realChain.httpStream();
        StreamAllocation streamAllocation = realChain.streamAllocation();
        RealConnection connection = (RealConnection) realChain.connection();
        Request request = realChain.request();

        long sentRequestMillis = System.currentTimeMillis();

        realChain.eventListener().requestHeadersStart(realChain.call());
        httpCodec.writeRequestHeaders(request);
        realChain.eventListener().requestHeadersEnd(realChain.call(), request);

        Response.Builder responseBuilder = null;
        if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
            // If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
            // Continue" response before transmitting the request body. If we don't get that, return
            // what we did get (such as a 4xx response) without ever transmitting the request body.
            if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
                httpCodec.flushRequest();
                realChain.eventListener().responseHeadersStart(realChain.call());
                responseBuilder = httpCodec.readResponseHeaders(true);
            }

            if (responseBuilder == null) {
                // Write the request body if the "Expect: 100-continue" expectation was met.
                realChain.eventListener().requestBodyStart(realChain.call());
                long contentLength = request.body().contentLength();
                CountingSink requestBodyOut =
                        new CountingSink(httpCodec.createRequestBody(request, contentLength));
                BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);

                request.body().writeTo(bufferedRequestBody);
                bufferedRequestBody.close();
                realChain.eventListener()
                        .requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
            } else if (!connection.isMultiplexed()) {
                // If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
                // from being reused. Otherwise we're still obligated to transmit the request body to
                // leave the connection in a consistent state.
                streamAllocation.noNewStreams();
            }
        }

        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
            responseBuilder = httpCodec.readResponseHeaders(false);

            response = responseBuilder
                    .request(request)
                    .handshake(streamAllocation.connection().handshake())
                    .sentRequestAtMillis(sentRequestMillis)
                    .receivedResponseAtMillis(System.currentTimeMillis())
                    .build();

            code = response.code();
        }

        realChain.eventListener()
                .responseHeadersEnd(realChain.call(), response);

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

注释告诉我们这就是真的网络请求了,妈的,到底如何请求的我就看不懂了,如果想完全搞懂,还是需要从倒数第二部,一点一点的断点喽。具体的http的请求过程。有机会再慢慢的验证,这里我就不管喽。以后慢慢分析到底如何创建socket的。

后记

这个东西写了挺久的,中间耽误了一周,这次凑数把它完成,希望以后可以补充完整。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值