OkHttp3

基本使用:

这里简单介绍2种,GET和POST.推荐让 OkHttpClient 保持单例,用同一个 OkHttpClient 实例来执行你的所有请求,因为每一个 OkHttpClient 实例都拥有自己的连接池和线程池,重用这些资源可以减少延时和节省资源,如果为每个请求创建一个 OkHttpClient实例,显然就是一种资源的浪费。

使用GET:

public static final String URL = "http://www.baidu.com";
private OkHttpClient mOkHttpClient = new OkHttpClient();
private final Request mRequest = new Request.Builder().url(URL).build();

@Override
public void request() {
    mOkHttpClient.newCall(mRequest)
            //异步请求
            .enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    e.printStackTrace();
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    Log.w(TAG, "onResponse: " + response.body().string());
                }
            });
}

使用POST:

public static final String URL = "https://api.github.com/markdown/raw";
private OkHttpClient mOkHttpClient = new OkHttpClient.Builder()
        .build();
MediaType mMediaType = MediaType.parse("text/x-markdown; charset=utf-8");
String requestBody = "I am xfhy.";
private final Request mRequest = new Request.Builder()
        .url(URL)
        .post(RequestBody.create(mMediaType, requestBody))
        .build();

@Override
public void request() {
    //每一个Call(其实现是RealCall)只能执行一次,否则会报异常
    mOkHttpClient.newCall(mRequest).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            e.printStackTrace();
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            Log.w(TAG, "onResponse: " + response.body().string());
        }
    });
}

interceptor 拦截器(重点):

OkHttpClient的Buidler,这里使用了建造者模式:

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

public Builder() {
  //任务调度器
  dispatcher = new Dispatcher();//创建一个新的 Dispatcher 对象并将其赋值给 dispatcher 属性。Dispatcher 可能用于处理任务的分发或调度。
  //支持的协议
  protocols = DEFAULT_PROTOCOLS;//将默认的协议设置赋值给 protocols 属性。这可能定义了所支持的网络协议,例如 HTTP、HTTPS 等。
  connectionSpecs = DEFAULT_CONNECTION_SPECS;//:为 connectionSpecs 属性赋予默认的连接规范。这可能包括连接的参数,如连接的类型、加密方式等。
  eventListenerFactory = EventListener.factory(EventListener.NONE);//创建一个 EventListener 工厂,并将其初始化为 NONE 状态。EventListener 可能用于监听和处理特定的事件。
  proxySelector = ProxySelector.getDefault();//获取默认的代理选择器并赋值给 proxySelector 属性。代理选择器用于确定网络请求是否通过代理服务器以及选择哪个代理服务器。
  if (proxySelector == null) {
    proxySelector = new NullProxySelector();//如果获取的默认代理选择器为空,则使用 NullProxySelector 作为替代。
  }
  cookieJar = CookieJar.NO_COOKIES;//将 CookieJar 设置为不存储任何 Cookie 的状态。CookieJar 用于管理与请求相关的 Cookie。
  socketFactory = SocketFactory.getDefault();//获取默认的套接字工厂。套接字工厂用于创建和管理套接字连接。
  hostnameVerifier = OkHostnameVerifier.INSTANCE;//设置主机名验证器为特定的实例。主机名验证用于确保连接的主机名与预期的匹配。
  certificatePinner = CertificatePinner.DEFAULT;//使用默认的证书固定策略。证书固定用于增强网络连接的安全性。
  proxyAuthenticator = Authenticator.NONE;//将代理认证器设置为无认证状态。
  authenticator = Authenticator.NONE;//将认证器设置为无认证状态
  //连接池
  connectionPool = new ConnectionPool();//创建一个新的连接池对象。连接池用于管理和复用连接,提高性能。
  dns = Dns.SYSTEM;//将 DNS 设置为使用系统默认的 DNS 配置。
  followSslRedirects = true;//表示允许跟随 SSL(安全套接字层)重定向。
  followRedirects = true;//允许跟随一般的重定向。
  retryOnConnectionFailure = true;//在连接失败时会自动重试。
  callTimeout = 0;//设置调用超时时间为 0,可能表示没有限制或使用其他逻辑来处理。
  //超时时间
  connectTimeout = 10_000;
  readTimeout = 10_000;
  writeTimeout = 10_000;
  pingInterval = 0;//设置 Ping 间隔为 0,可能表示不进行 Ping 操作或有特定的条件控制。
}

其中dispatcher 用于任务的分发和调度:

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

dispatcher 持有三个双向队列,按顺序:

  • 准备执行异步操作的任务队列
  • 正在执行的异步任务队列
  • 正在执行的同步任务

可以看出,应该网络请求被封装成了AsyncCallRealCall,其中AsyncCallRealCall的非静态内部类,也就是👇:

static class RealCall{

    final class AsyncCall{

    }

}
AsyncCall实现了NamedRunnable抽象类,抽象类其中使用模板设计模式,使AsyncCall实现excute方法,而这个方法就使我们进行网络操作的地方。
@Override protected void execute() {
      boolean signalledCallback = false;
      transmitter.timeoutEnter();
      try {
//获得网络请求结果的地方
        Response response = getResponseWithInterceptorChain();
        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 {
//回调接口
          responseCallback.onFailure(RealCall.this, e);
        }
      } catch (Throwable t) {
        cancel();
        if (!signalledCallback) {
          IOException canceledException = new IOException("canceled due to " + t);
          canceledException.addSuppressed(t);
          responseCallback.onFailure(RealCall.this, canceledException);
        }
        throw t;
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

进入getResponseWithInterceptorChain()方法:

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
//组装责任链
    interceptors.addAll(client.interceptors());
//负责请求的重定向操作,用于处理网络请求中,请求失败后的重试机制。
    interceptors.add(new RetryAndFollowUpInterceptor(client));
//主要是添加一些header
    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, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    boolean calledNoMoreExchanges = false;
    try {
 // 执行拦截器链,获取响应
      Response response = chain.proceed(originalRequest);
      if (transmitter.isCanceled()) {
        closeQuietly(response);
        throw new IOException("Canceled");
      }
      return response;
    } catch (IOException e) {
      calledNoMoreExchanges = true;
      throw transmitter.noMoreExchanges(e);
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null);
      }
    }
  }
}

总的来说:

  • 组装责任链的链
  • 调用chain的proceed方法获得网络请求的结果
  • 判断是否取消
  • 返回结果

我们进入proceed方法:

  public Response proceed(Request request, Transmitter transmitter, @Nullable Exchange exchange)
      throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.exchange != null && !this.exchange.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.exchange != 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, transmitter, exchange,
        index + 1, request, call, connectTimeout, readTimeout, writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (exchange != 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;
  }

注意这是一个递归调用,所以的拦截器都是从这个方法走到下一个拦截器。

当调用 proceed 方法时,它会取出下一个拦截器并执行其 intercept 方法。如果某个拦截器需要后续的拦截器获取响应,它可以通过传递当前的 RealInterceptorChain 对象再次调用 proceed 方法,从而实现拦截器的链式调用。这样,请求可以依次经过各个拦截器的处理,最后得到的响应也会反向依次经过拦截器进行可能的修改或其他操作,直到返回给最初的调用者。

建议:

将每一个拦截器的intercept方法堪看成两个部分,调用procedd方法作为分界线,上半部分是去请求,下半部分就是返回的结果了,所以下半部分的代码都是为了操作返回的结果。

开始调用第一个:

RetryAndFollowUpInterceptor拦截器

intercept方法:

@Override 
public Response intercept(Chain chain) throws IOException {
    // 获取链中的请求
    Request request = chain.request();
    // 强制类型转换为 RealInterceptorChain 类型
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    // 获取 Transmitter 对象
    Transmitter transmitter = realChain.transmitter();

    int followUpCount = 0;  // 初始化重定向计数为 0
    Response priorResponse = null;  // 初始化之前的响应为 null

    // 死循环,直到达到重定向的最大次数
    while (true) {
        // 准备一个流来承载请求,如果存在则复用
        transmitter.prepareToConnect(request);

        if (transmitter.isCanceled()) {  // 如果请求被取消
            throw new IOException("Canceled");  // 抛出异常
        }

        Response response;  // 声明响应变量
        boolean success = false;  // 标记请求是否成功的标志

        try {
            // 调用下一个拦截器
            response = realChain.proceed(request, transmitter, null);
            success = true;  // 设置成功标志为真
        } catch (RouteException e) {  // 捕获路由异常

            // 下面是一些失败然后又重新请求的代码

            // 如果无法从最后的连接异常中恢复,抛出第一个连接异常
            if (!recover(e.getLastConnectException(), transmitter, false, request)) {
                throw e.getFirstConnectException();
            }
            continue;  // 继续下一次循环
        } catch (IOException e) {  // 捕获输入输出异常

            // 一个与服务器通信的尝试失败。请求可能已被发送。
            boolean requestSendStarted =!(e instanceof ConnectionShutdownException);
            // 如果无法从异常中恢复,抛出异常
            if (!recover(e, transmitter, requestSendStarted, request)) throw e;
            continue;  // 继续下一次循环
        } finally {
            // 如果请求不成功,释放相关资源
            if (!success) {
                transmitter.exchangeDoneDueToException();
            }
        }

        // 如果之前有响应,
            }
        }

        // 如果之前有响应,将其附加到新的响应中
        if (priorResponse!= null) {
            response = response.newBuilder()
              .priorResponse(priorResponse.newBuilder()
                      .body(null)
                      .build())
              .build();
        }

        Exchange exchange = Internal.instance.exchange(response);  // 获取 Exchange 对象
        Route route = exchange!= null? exchange.connection().route() : null;  // 获取路由

        // 获取后续的请求
        Request followUp = followUpRequest(response, route);

        if (followUp == null) {  // 如果没有后续请求
            if (exchange!= null && exchange.isDuplex()) {  // 如果存在 Exchange 且为双向
                transmitter.timeoutEarlyExit();  // 提前退出超时
            }
            return response;  // 返回当前响应
        }

        RequestBody followUpBody = followUp.body();  // 获取后续请求的请求体
        if (followUpBody!= null && followUpBody.isOneShot()) {  // 如果请求体不为空且为一次性的
            return response;  // 返回当前响应
        }

        closeQuietly(response.body());  // 安静地关闭当前响应的主体
        if (transmitter.hasExchange()) {  // 如果 Transmitter 有 Exchange
            exchange.detachWithViolence();  // 强制分离 Exchange
        }

        if (++followUpCount > MAX_FOLLOW_UPS) {  // 如果重定向次数超过最大限制
            throw new ProtocolException("Too many follow-up requests: " + followUpCount);  // 抛出协议异常
        }

        request = followUp;  // 更新请求为后续请求
        priorResponse = response;  // 更新之前的响应
    }
}
  • 从传入的链中获取请求和相关对象。
  • 在一个死循环中:
    • 准备请求的连接。
    • 尝试调用下一个拦截器获取响应,处理可能出现的路由异常和输入输出异常。
    • 根据之前的响应和当前情况处理后续请求。
    • 处理请求体和 Exchange 的相关操作。
    • 控制重定向的次数,超过最大次数则抛出异常。
    • 更新请求和响应,以便进行下一轮处理。

开始调用第二个:

BridgeInterceptor 拦截器

它是一个连接桥.添加了很多header 

intercept方法:

@Override 
public Response intercept(Chain chain) throws IOException {
    // 获取用户发起的原始请求
    Request userRequest = chain.request();
    // 创建一个新的请求构建器,基于原始请求
    Request.Builder requestBuilder = userRequest.newBuilder();

    // 获取请求体
    RequestBody body = userRequest.body();
    if (body!= null) {
        // 获取请求体的内容类型
        MediaType contentType = body.contentType();
        if (contentType!= null) {
            // 设置"Content-Type"请求头
            requestBuilder.header("Content-Type", contentType.toString());
        }

        // 获取请求体的内容长度
        long contentLength = body.contentLength();
        if (contentLength!= -1) {
            // 设置"Content-Length"请求头,并移除"Transfer-Encoding"请求头
            requestBuilder.header("Content-Length", Long.toString(contentLength));
            requestBuilder.removeHeader("Transfer-Encoding");
        } else {
            // 设置"Transfer-Encoding"请求头为"chunked",并移除"Content-Length"请求头
            requestBuilder.header("Transfer-Encoding", "chunked");
            requestBuilder.removeHeader("Content-Length");
        }
    }

    // 如果请求中没有"Host"请求头,添加
    if (userRequest.header("Host") == null) {
        requestBuilder.header("Host", hostHeader(userRequest.url(), false));
    }

    // 如果请求中没有"Connection"请求头,添加"Keep-Alive"
    if (userRequest.header("Connection") == null) {
        requestBuilder.header("Connection", "Keep-Alive");
    }

    // 处理透明的 gzip 压缩
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
        transparentGzip = true;
        requestBuilder.header("Accept-Encoding", "gzip");
    }

    // 加载与请求 URL 相关的 Cookie 并设置请求头
    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
        requestBuilder.header("Cookie", cookieHeader(cookies));
    }

    // 如果请求中没有"User-Agent"请求头,添加
    if (userRequest.header("User-Agent") == null) {
        requestBuilder.header("User-Agent", Version.userAgent());
    }

    // 执行链中的下一个拦截器,获取网络响应
    Response networkResponse = chain.proceed(requestBuilder.build());

    // 将响应的 Cookie 信息保存到 CookieJar 中
    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

    // 创建一个新的响应构建器,基于网络响应
    Response.Builder responseBuilder = networkResponse.newBuilder()
       .request(userRequest);

    // 处理透明的 gzip 解压
    if (transparentGzip
        && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
        && HttpHeaders.hasBody(networkResponse)) {
        GzipSource responseBody = new GzipSource(networkResponse.body().source());
        Headers strippedHeaders = networkResponse.headers().newBuilder()
          .removeAll("Content-Encoding")
          .removeAll("Content-Length")
          .build();
        responseBuilder.headers(strippedHeaders);
        String contentType = networkResponse.header("Content-Type");
        responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
    }

    // 构建并返回最终的响应
    return responseBuilder.build();
}

将封装的request打开,拿信息。

  1. 对原始请求进行一些请求头的补充和修改,包括 Content-TypeContent-LengthTransfer-EncodingHostConnectionAccept-EncodingCookieUser-Agent 等。
  2. 执行链中的下一个拦截器,获取网络响应。
  3. 处理响应中的 Cookie 信息。
  4. 对于支持透明 gzip 压缩的响应,进行解压处理并更新响应头和响应体。
  5. 构建并返回最终的响应。

第三个:

CacheInterceptor拦截器

intercept方法:

@Override 
public Response intercept(Chain chain) throws IOException {
    // 尝试从缓存中获取与请求匹配的候选响应
    Response cacheCandidate = cache!= null? cache.get(chain.request()) : null;

    // 获取当前时间
    long now = System.currentTimeMillis();

    // 根据当前时间、请求和候选缓存响应计算缓存策略
    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
    // 获取根据策略确定的网络请求
    Request networkRequest = strategy.networkRequest;
    // 获取根据策略确定的缓存响应
    Response cacheResponse = strategy.cacheResponse;

    if (cache!= null) {
        // 让缓存跟踪响应策略
        cache.trackResponse(strategy);
    }

    // 如果有候选缓存响应但最终的缓存响应为空,关闭候选缓存响应的主体
    if (cacheCandidate!= null && cacheResponse == null) {
        closeQuietly(cacheCandidate.body()); 
    }

    // 如果禁止使用网络且缓存不满足,返回错误响应
    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();
    }

    // 如果不需要网络请求(完全使用缓存),返回缓存响应
    if (networkRequest == null) {
        return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }

    Response networkResponse = null;
    try {
        // 执行网络请求
        networkResponse = chain.proceed(networkRequest);
    } finally {
        // 如果网络响应为空且有候选缓存响应,关闭候选缓存响应的主体
        if (networkResponse == null && cacheCandidate!= null) {
            closeQuietly(cacheCandidate.body());
        }
    }

    // 如果有缓存响应且网络响应的状态码是 304(未修改)
    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();

            // 跟踪条件缓存命中并更新缓存
            cache.trackConditionalCacheHit();
            cache.update(cacheResponse, response);
            return response;
        } else {
            // 关闭缓存响应的主体
            closeQuietly(cacheResponse.body());
        }
    }

    // 创建基于网络响应的新响应
    Response response = networkResponse.newBuilder()
      .cacheResponse(stripBody(cacheResponse))
      .networkResponse(stripBody(networkResponse))
      .build();

    if (cache!= null) {
        // 如果响应有主体且可缓存,尝试将其放入缓存
        if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
            CacheRequest cacheRequest = cache.put(response);
            return cacheWritingResponse(cacheRequest, response);
        }

        // 如果网络请求方法会使缓存失效,尝试从缓存中移除
        if (HttpMethod.invalidatesCache(networkRequest.method())) {
            try {
                cache.remove(networkRequest);
            } catch (IOException ignored) {
                // 忽略移除缓存时的异常
            }
        }
    }

    // 返回最终的响应
    return response;
}

主要用于处理缓存相关的逻辑:

  1. 首先尝试从缓存中获取与当前请求匹配的候选响应。
  2. 根据当前时间、请求和候选缓存响应计算缓存策略,确定是否需要发起网络请求以及如何使用缓存响应。
  3. 如果禁止使用网络且缓存不满足,返回错误响应。
  4. 如果完全不需要网络请求,直接使用缓存响应。
  5. 执行网络请求后,根据不同情况处理缓存响应和网络响应的组合。
  6. 对于条件获取(网络响应为未修改)的情况,进行头信息合并、缓存更新等操作。
  7. 最后,根据响应是否可缓存以及网络请求方法的影响,对缓存进行相应的操作(放入缓存或移除)。

第四个:

ConnectInterceptor拦截器

intercept:

@Override 
public Response intercept(Chain chain) throws IOException {
    // 进行类型强制转换,将传入的链转换为 RealInterceptorChain 类型
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    // 获取链中的请求
    Request request = realChain.request();
    // 获取链中的 Transmitter 对象
    Transmitter transmitter = realChain.transmitter();

    // 判断请求方法是否为 "GET",如果不是则需要进行更广泛的健康检查
    boolean doExtensiveHealthChecks =!request.method().equals("GET");
    // 创建一个新的 Exchange 对象
    Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks);

    // 调用 RealInterceptorChain 的 proceed 方法执行下一个拦截器,并返回响应
    return realChain.proceed(request, transmitter, exchange);
}
  1. 进行类型转换,获取请求和 Transmitter 对象。
  2. 根据请求方法判断是否需要进行更广泛的健康检查。
  3. 创建新的 Exchange 对象。
  4. 调用 RealInterceptorChain 的 proceed 方法继续执行拦截器链,并返回得到的响应

第五个:

CallServerInterceptor拦截器:

intercept:

@Override 
public Response intercept(Chain chain) throws IOException {
    // 进行类型转换,获取 RealInterceptorChain 对象
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    // 获取 Exchange 对象和请求
    Exchange exchange = realChain.exchange();
    Request request = realChain.request();

    // 记录发送请求的时间
    long sentRequestMillis = System.currentTimeMillis();

    // 写入请求头
    exchange.writeRequestHeaders(request);

    boolean responseHeadersStarted = false;
    Response.Builder responseBuilder = null;

    // 如果请求方法允许请求体且请求体不为空
    if (HttpMethod.permitsRequestBody(request.method()) && request.body()!= null) {
        // 如果请求头中有"Expect: 100-continue"
        if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
            // 刷新请求并开始处理响应头
            exchange.flushRequest();
            responseHeadersStarted = true;
            exchange.responseHeadersStart();
            // 读取响应头
            responseBuilder = exchange.readResponseHeaders(true);
        }

        // 如果没有获取到响应头构建器
        if (responseBuilder == null) {
            // 如果请求体是双向的
            if (request.body().isDuplex()) {
                // 准备双向请求体
                exchange.flushRequest();
                BufferedSink bufferedRequestBody = Okio.buffer(
                    exchange.createRequestBody(request, true));
                request.body().writeTo(bufferedRequestBody);
            } else {
                // 写入请求体
                BufferedSink bufferedRequestBody = Okio.buffer(
                    exchange.createRequestBody(request, false));
                request.body().writeTo(bufferedRequestBody);
                bufferedRequestBody.close();
            }
        } else {
            // 不需要请求体
            exchange.noRequestBody();
            if (!exchange.connection().isMultiplexed()) {
                // 防止 HTTP/1 连接被复用
                exchange.noNewExchangesOnConnection();
            }
        }
    } else {
        // 没有请求体的情况
        exchange.noRequestBody();
    }

    // 如果请求体为空或不是双向的,完成请求
    if (request.body() == null ||!request.body().isDuplex()) {
        exchange.finishRequest();
    }

    // 如果响应头还未开始
    if (!responseHeadersStarted) {
        exchange.responseHeadersStart();
    }

    // 如果还没有响应构建器,读取响应头创建
    if (responseBuilder == null) {
        responseBuilder = exchange.readResponseHeaders(false);
    }

    // 构建并返回响应
    Response response = responseBuilder
      .request(request)
      .handshake(exchange.connection().handshake())
      .sentRequestAtMillis(sentRequestMillis)
      .receivedResponseAtMillis(System.currentTimeMillis())
      .build();

    // 处理特殊的响应码 100
    int code = response.code();
    if (code == 100) {
        // 重新读取实际响应
        response = exchange.readResponseHeaders(false)
          .request(request)
          .handshake(exchange.connection().handshake())
          .sentRequestAtMillis(sentRequestMillis)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build();

        code = response.code();
    }

    // 结束响应头处理
    exchange.responseHeadersEnd(response);

    // 处理 WebSocket 特殊情况
    if (forWebSocket && code == 101) {
        // 升级连接,处理响应体
        response = response.newBuilder()
          .body(Util.EMPTY_RESPONSE)
          .build();
    } else {
        // 打开并设置响应体
        response = response.newBuilder()
          .body(exchange.openResponseBody(response))
          .build();
    }

    // 处理"Connection"头
    if ("close".equalsIgnoreCase(response.request().header("Connection"))
        || "close".equalsIgnoreCase(response.header("Connection"))) {
        exchange.noNewExchangesOnConnection();
    }

    // 处理特殊的响应码和内容长度不一致的情况
    if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
        throw new ProtocolException(
            "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
    }

    return response;
}

主要是在拦截器中处理网络请求的发送和响应的接收及处理,包括以下主要步骤:

  1. 准备和发送请求头。
  2. 根据请求方法和请求体的情况进行不同的处理,包括处理 Expect: 100-continue 头、写入请求体等。
  3. 读取和处理响应头,构建响应对象。
  4. 对特殊的响应码(如 100101204205)进行特殊处理。
  5. 处理 Connection 头。
  6. 检查响应码和内容长度的一致性,处理异常情况。

拿到数据之后再沿着链返回。

Request:

Request感觉就是一个请求的封装.它里面封装了url、method、header、body,该有的都有了.而且它也是用构造器模式来构建的,它默认的请求方式是GET

public final class Request {
  final HttpUrl url;
  final String method;
  final Headers headers;
  final @Nullable RequestBody body;
  final Map<Class<?>, Object> tags;


 public Builder() {
  this.method = "GET";
  this.headers = new Headers.Builder();
 }
    
  public static class Builder {
    @Nullable HttpUrl url;
    String method;
    Headers.Builder headers;
    @Nullable RequestBody body;

    /** A mutable map of tags, or an immutable empty map if we don't have any. */
    Map<Class<?>, Object> tags = Collections.emptyMap();

    public Builder() {
      this.method = "GET";
      this.headers = new Headers.Builder();
    }
}

最终的精髓;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值