OkHttp网络请求框架源码解析二

本文深入解析OkHttp网络请求框架中的核心知识——拦截器机制。详细介绍了五个关键拦截器的作用与实现流程,包括RetryAndFollowUpInterceptor、BridgeInterceptor、CacheInterceptor、ConnectInterceptor和CallServerInterceptor,帮助读者理解OkHttp如何高效处理网络请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

OkHttp网络请求框架源码解析二

 

本篇讲解OkHttp核心知识拦截器,共有5个拦截器,分别为RetryAndFollowUpInterceptor,BridgeInterceptor, CacheInterceptor,ConnectInterceptor 和 CallServerInterceptor。下面一一讲到。

//上一篇讲到,作为Runnable的 AsyncCall,最终的execute()方法为RealCall里面的execute()方法。
@Override protected void execute() {
     
        //获取响应回来的数据response
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          
          //回调onFailure
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          
          //回调onResponse
          responseCallback.onResponse(RealCall.this, response);
        }
      
        ......
        
        //线程池执行完线程任务后,调用此方法.
        client.dispatcher().finished(this);
 
 
    }



//不管是同步请求,还是异步请求,都是通过getResponseWithInterceptorChain方法获取响应。
Response getResponseWithInterceptorChain() throws IOException {

    List<Interceptor> interceptors = new ArrayList<>();

    //添加用户自定义的拦截器
    interceptors.addAll(client.interceptors());

    ......

    //创建拦截器链    
    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    
    //创建下一个拦截器链
    return chain.proceed(originalRequest);
  }


//chain.proceed()方法实现
public Response proceed() throws IOException {
    
    ......
    
    //创建下一个拦截器链 index+1
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, streamAllocation, httpCodec, connection, index + 1, request);

    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    return response;
  }




第一个拦截器,重试重定向拦截器:RetryAndFollowUpInterceptor。

1.创建StreamAllocation对象;

2.调用RealInterceptorChain.proceed()方法进行网络请求;

3.根据结果判断是否重新请求;

4.调用下一个拦截器;


//RetryAndFollowUpInterceptor拦截器里面的核心方法intercept(),
@Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();

    //StreamAllocation 获取建立Http连接的所有网络组件
    //虽然在这里被创建,但是这里没有使用。
    streamAllocation = new StreamAllocation(
        client.connectionPool(), createAddress(request.url()), callStackTrace);

    ......

    //重试次数20次
     if (++followUpCount > 20) {
        streamAllocation.release();      
      }

}

第二个拦截器,桥接拦截器,BridgeInterceptor。

1.将request请求转换成可以进行网络访问的请求;

2.进行网络请求;

3.将响应response转换成客户度可以用的response。

//BridgeInterceptor桥接拦截器的核心方法intercept()
Request userRequest = chain.request();
    Request.Builder requestBuilder = userRequest.newBuilder();

    RequestBody body = userRequest.body();
   
      给Request添加各种头部信息
      requestBuilder.header("Content-Type", contentType.toString());    

      long contentLength = body.contentLength();
      if (contentLength != -1) {
        requestBuilder.header("Content-Length", Long.toString(contentLength));
      } else {
        requestBuilder.header("Transfer-Encoding", "chunked");
      }
    }

      ......

      requestBuilder.header("Host", hostHeader(userRequest.url(), false));
      requestBuilder.header("Connection", "Keep-Alive");
    
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");
    }

      List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
      requestBuilder.header("Cookie", cookieHeader(cookies));
      requestBuilder.header("User-Agent", Version.userAgent());
    
    //从服务器获取response
    Response networkResponse = chain.proceed(requestBuilder.build());

    //将服务器返回的数据头部转换成客户端可以接收的形式
    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), 
    networkResponse.headers());

第三个拦截器,缓存拦截器CacheInterceptor。

 //CacheInterceptor核心方法intercept
 @Override public Response intercept(Chain chain) throws IOException {
        
    //获取缓存
    Response cacheCandidate = cache != null
        ? cache.get(chain.request())
        : null;

    //创建CacheStrategy
    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(),         
    cacheCandidate).get();
    Request networkRequest = strategy.networkRequest;
    Response cacheResponse = strategy.cacheResponse;

    //关于缓存命中率,如果使用了缓存,则hitCount++。
    cache.trackResponse(strategy);
    

    //第一种情况,如果不能使用网络,并且没有缓存,则OkHttp内部构建一个504响应作为response。
    if (networkRequest == null && cacheResponse == null) {
      return new Response.Builder()
          .request(chain.request())
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(Util.EMPTY_RESPONSE)
          .sentRequestAtMillis(-1L)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build();
    }

    //第二种情况,不能使用网络,但是有缓存,则使用缓存作为response。
    if (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }

    //第三种情况,可以使用网络,不管是否有缓存都会调用chain.proceed方法进行网络请求。
    Response networkResponse = null;
    networkResponse = chain.proceed(networkRequest);
   
    //如果有缓存,并且服务器响应码为304,表示内容未被修改,则使用缓存作为response.
    if (cacheResponse != null) {
      if (networkResponse.code() == HTTP_NOT_MODIFIED) {
        Response response = cacheResponse.newBuilder()
            .headers(combine(cacheResponse.headers(), networkResponse.headers()))
            .sentRequestAtMillis(networkResponse.sentRequestAtMillis())
            .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build();
        networkResponse.body().close();

        return response;
      } 
    }
    
    //如果没有缓存,则将刚才网络请求的response作为response.
    Response response = networkResponse.newBuilder()
        .cacheResponse(stripBody(cacheResponse))
        .networkResponse(stripBody(networkResponse))
        .build();

    //如果代码能走到这里,说明前面网络请求的响应码不是304,表示response被修改了,则更新缓存。
    if (cache != null) {
       
      //条件判断
      if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
        
        //存入新的缓存
        CacheRequest cacheRequest = cache.put(response);
        return cacheWritingResponse(cacheRequest, response);
      }

      //假如请求方式不是get,则删除缓存,因为OkHttp只对get方式的请求进行缓存。
      if (HttpMethod.invalidatesCache(networkRequest.method())) {
        cache.remove(networkRequest);
      }
    }

    return response;
  }

第四个拦截器,连接池拦截器,ConnectInterceptor。


//ConnectInterceptor整个类的代码
public final class ConnectInterceptor implements Interceptor {
  public final OkHttpClient client;

  public ConnectInterceptor(OkHttpClient client) {
    this.client = client;
  }

  @Override public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    
    //StreamAllocation用来获取网络请求需要的所有组件
    StreamAllocation streamAllocation = realChain.streamAllocation();
    

    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    
    //HttpCodec用来 编码request,解码response
    HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);

    //RealConnection 进行实际的网络io传输
    RealConnection connection = streamAllocation.connection();

    //将重要的HttpCodec对象和RealConnection对象传递给后面的拦截器
    return realChain.proceed(request, streamAllocation, httpCodec, connection);
  }
}


//streamAllocation.newStream方法的实现
public HttpCodec newStream(OkHttpClient client, boolean doExtensiveHealthChecks) {
   
      //通过findHealthyConnection方法获取RealConnection
      RealConnection resultConnection = findHealthyConnection(connectTimeout,     
      readTimeout,writeTimeout,connectionRetryEnabled, doExtensiveHealthChecks);

      //通过RealConnection的newCodec方法获取HttpCodec对象,最后返回。
      HttpCodec resultCodec = resultConnection.newCodec(client, this);

      synchronized (connectionPool) {
        codec = resultCodec;
        return resultCodec;
      }
   
  }


//findHealthyConnection方法的实现
private RealConnection findHealthyConnection(){
    while (true) {

      //循环里面,通过findConnection()方法获取RealConnection对象。然后返回。
      RealConnection candidate = findConnection(connectTimeout, readTimeout, 
      writeTimeout,
      connectionRetryEnabled);
      synchronized (connectionPool) {
        if (candidate.successCount == 0) {
          return candidate;
        }
      }

    ......

  }


//findConnection()方法的实现
private RealConnection findConnection(){

    //先复用已有的连接,如果满足条件,则返回
    RealConnection allocatedConnection = this.connection;
      if (allocatedConnection != null && !allocatedConnection.noNewStreams) {
        return allocatedConnection;
      }

    //如果不能复用,则从连接池connectionPool里面获取RealConnection对象。
    Internal.instance.get(connectionPool, address, this, null);
      if (connection != null) {
        return connection;
      }

    //调用RealConnection对象的connect()方法进行实际的网络请求连接
    result.connect(connectTimeout, readTimeout, writeTimeout, 
    connectionRetryEnabled);

    //然后把上面的连接放入连接池connectionPool      
    Internal.instance.put(connectionPool, result);


}

第五个拦截器,CallServerInterceptor。

//CallInterceptor拦截器的核心方法实现 
 @Override public Response intercept(Chain chain) throws IOException {

    //5个重要的对象,第一个:拦截器链
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    //5个重要的对象,第二个:HttpCodec编码request,解码response
    HttpCodec httpCodec = realChain.httpStream();
    //5个重要的对象,第三个:分配网络请求组件
    StreamAllocation streamAllocation = realChain.streamAllocation();
    //5个重要的对象,第四个:真正的网络请求
    RealConnection connection = (RealConnection) realChain.connection();
    //5个重要的对象,第五个:
    Request request = realChain.request();

    //第一步:写请求头。
    httpCodec.writeRequestHeaders(request);
    //第二步:写请求体
    request.body().writeTo(bufferedRequestBody);
    //第三步:结束请求
    httpCodec.finishRequest();    
    //第四步:读取response请求头
    responseBuilder = httpCodec.readResponseHeaders(false);
    //第五步:读取response请求体
    response = response.newBuilder()
          .body(httpCodec.openResponseBody(response))
          .build();



}


 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值