okhttp3实例源码浅析(2)-拦截器机制

okhttp在发起网络请求过程中使用了拦截器机制,逐层对request和response做处理

// 关键方法
Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors()); // 添加自定义拦截器,可以通过builder.addInterceptor()方法添加
    interceptors.add(retryAndFollowUpInterceptor); // 重试、重定向拦截器
    interceptors.add(new BridgeInterceptor(client.cookieJar())); // 编解码、压缩解压拦截器
    interceptors.add(new CacheInterceptor(client.internalCache())); // 缓存拦截器
    interceptors.add(new ConnectInterceptor(client)); // 复用连接池拦截器
    if (!forWebSocket) { // forWebSocket默认为false
      interceptors.addAll(client.networkInterceptors()); // 添加自定义拦截器,可以通过builder.addNetworkInterceptor()方法添加
    }
    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);
}

okhttp中有两种拦截器:

  1. interceptors 处理应用层业务逻辑
  2. networkInterceptors 处理网络层逻辑
    networkInterceptors在interceptors之后处理,如果前面的拦截器处理了请求直接返回结果,后面的拦截器就不会执行,例如CacheInterceptor中如果命中缓存,就不会再往下走。

添加完拦截器后,创建拦截链RealInterceptorChain,然后调用拦截链的proceed方法并返回方法执行结果。
创建拦截链
创建RealInterceptorChain时传入的值说明:

  • interceptors:传入保存了拦截器的List
  • 0:索引,初始0。表示当前执行到第几层拦截器,通过它从interceptors取出拦截器执行
  • originalRequest:我们创建的原始Request

下面分析RealInterceptorChain的proceed方法

public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++; // 正常情况下这里执行完calls=1,用于校验拦截器是否只调用了一次proceed

	// 第一次执行时,streamAllocation、httpCodec、connection都为null
    // If we already have a stream, confirm that the incoming request will use it.
    if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    if (this.httpCodec != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout); // 新建一个拦截链,传入index+1
    Interceptor interceptor = interceptors.get(index); // 取出当前索引的拦截器
    Response response = interceptor.intercept(next); // 调用拦截器的intercept方法,并传入新的拦截链

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    if (response.body() == null) {
      throw new IllegalStateException(
          "interceptor " + interceptor + " returned a response with no body");
    }

    return response;
}

这个方法的关键就是根据index取出拦截器,再调用拦截器的intercept方法并传入新的拦截链。
每个拦截器需要继承Interceptor接口实现intercept方法,在intercept方法中需要实现以下主要步骤

@Override public Response intercept(Chain chain) throws IOException {
	Request request = chain.request(); // 从chain中取出request
	//todo 可以对request做修改或打印等扩展操作
	···
	//todo 判断如果满足某些条件直接返回response
	if(checkHit()) {
		return new Response.Builder().request(chain.request()).build();
	}
	//todo 执行拦截链的proceed方法,调用下一个拦截器,获取Response
	Response response = chain.proceed(request);
	//todo 可以对response做修改或打印等扩展操作
	···
	//todo 返回response给上一层
	return response;
}

request经过拦截链层层拦截处理,最终到最底层的拦截器CallServerInterceptor,由它真正向服务端发起请求和获取响应,最后再将response层层往外传递给调用者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值