OkHttp3初探:主流程源码分析

目录

一、OkHttp3请求流程图

二、主要流程

2.1 创建一个Http客户端:

2.2 组装Request对象

2.2.1 Request

2.2.2 RequestBody

2.3 请求网络核心代码(同步)

2.4 请求网络核心代码(异步)

2.4.1 Call接口

2.4.2 newCall()

2.4.3 RealCall.newRealCall()

2.4.4 RealCall.execute()

2.4.5 RealInterceptorChain.proceed()

2.4.6 Dispatcher

2.4.7 Response

三、主要参考


一、OkHttp3请求流程图

OkHttp请求流程图(图源见参考链接)
OkHttp请求流程图(图源@ Ho0229 详见参考链接)

 

二、主要流程

2.1 创建一个Http客户端:

OkHttpClient client = new OkHttpClient(); 
/** OkHttpClient()调用链条 */
/** 贴出源码,旨在有需要时可直接索引重要参数*/
public OkHttpClient() {
  this(new Builder());
}

/** 传入Builder以创建一个OkHttpClient */
OkHttpClient(Builder builder) {
    this.dispatcher = builder.dispatcher;
    this.proxy = builder.proxy;
    this.protocols = builder.protocols;
    this.connectionSpecs = builder.connectionSpecs;
    this.interceptors = Util.immutableList(builder.interceptors);
    this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
    this.eventListenerFactory = builder.eventListenerFactory;
    this.proxySelector = builder.proxySelector;
    this.cookieJar = builder.cookieJar;
    this.cache = builder.cache;
    this.internalCache = builder.internalCache;
    this.socketFactory = builder.socketFactory;

    boolean isTLS = false;
    for (ConnectionSpec spec : connectionSpecs) {
      isTLS = isTLS || spec.isTls();
    }

    if (builder.sslSocketFactory != null || !isTLS) {
      this.sslSocketFactory = builder.sslSocketFactory;
      this.certificateChainCleaner = builder.certificateChainCleaner;
    } else {
      X509TrustManager trustManager = Util.platformTrustManager();
      this.sslSocketFactory = newSslSocketFactory(trustManager);
      this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
    }

    if (sslSocketFactory != null) {
      Platform.get().configureSslSocketFactory(sslSocketFactory);
    }

    this.hostnameVerifier = builder.hostnameVerifier;
    this.certificatePinner = builder.certificatePinner.withCertificateChainCleaner(
        certificateChainCleaner);
    this.proxyAuthenticator = builder.proxyAuthenticator;
    this.authenticator = builder.authenticator;
    this.connectionPool = builder.connectionPool;
    this.dns = builder.dns;
    this.followSslRedirects = builder.followSslRedirects;
    this.followRedirects = builder.followRedirects;
    this.retryOnConnectionFailure = builder.retryOnConnectionFailure;
    this.callTimeout = builder.callTimeout;
    this.connectTimeout = builder.connectTimeout;
    this.readTimeout = builder.readTimeout;
    this.writeTimeout = builder.writeTimeout;
    this.pingInterval = builder.pingInterval;

    if (interceptors.contains(null)) {
      throw new IllegalStateException("Null interceptor: " + interceptors);
    }
    if (networkInterceptors.contains(null)) {
      throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
    }
  }

/** Builder是OkHttpClient的静态内部类 @OkHttpClient.class*/
// public static final class Builder {}
// Builder类重要参数
	Dispatcher dispatcher;
    @Nullable Proxy proxy;
    List<Protocol> protocols;
    List<ConnectionSpec> connectionSpecs;
    final List<Interceptor> interceptors = new ArrayList<>();
    final List<Interceptor> networkInterceptors = new ArrayList<>();
    EventListener.Factory eventListenerFactory;
    ProxySelector proxySelector;
    CookieJar cookieJar;
    @Nullable Cache cache;
    @Nullable InternalCache internalCache;
    SocketFactory socketFactory;
    @Nullable SSLSocketFactory sslSocketFactory;
    @Nullable CertificateChainCleaner certificateChainCleaner;
    HostnameVerifier hostnameVerifier;
    CertificatePinner certificatePinner;
    Authenticator proxyAuthenticator;
    Authenticator authenticator;
    ConnectionPool connectionPool;
    Dns dns;
    boolean followSslRedirects;
    boolean followRedirects;
    boolean retryOnConnectionFailure;
    int callTimeout;
    int connectTimeout;
    int readTimeout;
    int writeTimeout;
    int pingInterval;

// 构造方法
    public Builder() {
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      proxySelector = ProxySelector.getDefault();
      if (proxySelector == null) {
        proxySelector = new NullProxySelector();
      }
      cookieJar = CookieJar.NO_COOKIES;
      socketFactory = SocketFactory.getDefault();
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      certificatePinner = CertificatePinner.DEFAULT;
      proxyAuthenticator = Authenticator.NONE;
      authenticator = Authenticator.NONE;
      connectionPool = new ConnectionPool();
      dns = Dns.SYSTEM;
      followSslRedirects = true;
      followRedirects = true;
      retryOnConnectionFailure = true;
      callTimeout = 0;
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
      pingInterval = 0;
    }

    Okhttp中有client.internalCache()和client.connectionPool()两个重要的概念,前者管理网络访问的缓存信息,后者用于存储已链接的RealConnection(该RealConnection已经跟对应的hostname完成了三次握手)。

/** 
    cache域在我们构造OkHttpClient的时候是没有被初始化的,因此如果我们没有通过
调用Builder的cache方法设置cache值的话,该方法返回的对象实际上是一个不支持任何
缓存操作的对象,即该对象的所有方法为空。因此如果需要OkHttpClient支持缓存,需要
我们写一个Cache对象并在构造OkHttpClient的时候将其传给OkHttpClient。
*/
/** internalCache()@OkHttpClient.class */
InternalCache internalCache() {  
    return cache != null ? cache.internalCache : internalCache;  
} 

/** cache()@Builder.class@OkHttpClient.class */
/** 完成cache的初始化,如果不调用该方法那么OkHttpClient默认不提供Cache功能;*/
public Builder cache(Cache cache) {  
      this.cache = cache;  
      this.internalCache = null;  
      return this;  
}  

/** connectionPool()@OkHttpClient.class */
/** connectionPool的初始化是在构建OkHttpClient时创建的,调用的构造器为new ConnectionPool();*/
public ConnectionPool connectionPool() {  
    return connectionPool;   
}  

2.2 组装Request对象

2.2.1 Request

采用建造者(Builder)模式创建

/** Request类主要变量 */

private final HttpUrl url;  //目标地址  
private final String method; //方法  
//请求头,Headers.class里面维护了一个private final String[] namesAndValues;数据集  
private final Headers headers; 
private final RequestBody body; //请求表单  
private final Object tag; //标签  
private volatile URI javaNetUri; // Lazily initialized.  
private volatile CacheControl cacheControl; // Lazily initialized. 

/** 内部Builder类 */
/** public static class Builder {} */
/** 构造函数 */
public Builder() {  
  // 默认是 GET 方法
  this.method = "GET";  
  this.headers = new Headers.Builder();  
}  

/** build()方法 */
public Request build() {  
      if (url == null) throw new IllegalStateException("url == null");  
      return new Request(this);  
}  
// GET示例
Request request = new Request.Builder()
                .url("http://www.baidu.com")
                .build();

2.2.2 RequestBody

对于Post请求还须使用Request.Builder().post()方法,并传入RequestBody参数,可以为null;

/** RequestBody.class */
/** 多个重载的create()方法 */
/**
   * Returns a new request body that transmits {@code content}. If {@code contentType} is non-null
   * and lacks a charset, this will use UTF-8.
   */
 /** JSON类型RequestBody */
  public static RequestBody create(@Nullable MediaType contentType, String content) {
    Charset charset = UTF_8;
    if (contentType != null) {
      charset = contentType.charset();
      if (charset == null) {
        charset = UTF_8;
        contentType = MediaType.parse(contentType + "; charset=utf-8");
      }
    }
    byte[] bytes = content.getBytes(charset);
    return create(contentType, bytes);
  }

  /** Returns a new request body that transmits the content of {@code file}. */
  /** 文件类型RequestBody */
  public static RequestBody create(final @Nullable MediaType contentType, final File file) {
    if (file == null) throw new NullPointerException("file == null");

    return new RequestBody() {
      @Override public @Nullable MediaType contentType() {
        return contentType;
      }

      @Override public long contentLength() {
        return file.length();
      }

      @Override public void writeTo(BufferedSink sink) throws IOException {
        try (Source source = Okio.source(file)) {
          sink.writeAll(source);
        }
      }
    };
  }

/** Returns a new request body that transmits {@code content}. */
  public static RequestBody create(final @Nullable MediaType contentType, 
                                   final ByteString content) {
    return new RequestBody() {
      @Override public @Nullable MediaType contentType() {
        return contentType;
      }

      @Override public long contentLength() throws IOException {
        return content.size();
      }

      @Override public void writeTo(BufferedSink sink) throws IOException {
        sink.write(content);
      }
    };
  }

  /** Returns a new request body that transmits {@code content}. */
  public static RequestBody create(final @Nullable MediaType contentType, 
                                   final byte[] content) {
    return create(contentType, content, 0, content.length);
  }

  /** Returns a new request body that transmits {@code content}. */
  /** 字节流类型RequestBody */
  public static RequestBody create(final @Nullable MediaType contentType, final byte[] content,
      final int offset, final int byteCount) {
    if (content == null) throw new NullPointerException("content == null");
    Util.checkOffsetAndCount(content.length, offset, byteCount);
    return new RequestBody() {
      @Override public @Nullable MediaType contentType() {
        return contentType;
      }

      @Override public long contentLength() {
        return byteCount;
      }

      @Override public void writeTo(BufferedSink sink) throws IOException {
        sink.write(content, offset, byteCount);
      }
    };
  }
// POST之RequestBody示例
// 数据类型为json格式
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
// json数据
String jsonStr = "{\"key_one\":\"value_one\",\"key_two\":\"value_two\"}"; 
RequestBody body = RequestBody.create(josnStr, JSON);

2.3 请求网络核心代码(同步)

client.newCall(request).execute();

2.4 请求网络核心代码(异步)

client.newCall(request).enqueue(new Callback{...});

不管是同步还是异步,都需要获取Call对象,然后调用不同的线程管理方法去执行网络请求,下面详解。

2.4.1 Call接口

/**
 * A call is a request that has been prepared for execution. A call can be canceled. 
 * As this object represents a single request/response pair (stream), 
 * it cannot be executed twice.
 * Call是用来执行的具体请求,可以被取消,但因为其是个流对象,所以只能执行一次。
 */
public interface Call extends Cloneable { 
/**
   * 请求方法
   */
  Request request();

 /**
   * 同步请求方法
   */
  Response execute() throws IOException;

  /**
   * 异步请求方法
   */
  void enqueue(Callback responseCallback);

  /**
   * 取消请求调用
   */
  void cancel();

  /**
   * 判断请求调用是否执行 
   */
  boolean isExecuted();

  /**
   * 判断请求调用是否取消
   */
  boolean isCanceled();

  /**
   * 克隆一个请求调用
   */
  Call clone();

  /**
   * 工厂接口,OkHttpClient类重写
   */
	interface Factory {
    Call newCall(Request request);
  }
}

2.4.2 newCall()

/**
 * OkHttpClient方法 
 * Prepares the {@code request} to be executed at some point in the future.
 * 准备request网络请求 在将来某个时候执行。
 */
 @Override 
 public Call newCall(Request request) {
    /** this 即 OkHttpClient */
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

2.4.3 RealCall.newRealCall()

/** newRealCall@RealCall.class */
/** RealCall类的静态方法 */
static RealCall newRealCall(OkHttpClient client, Request originalRequest,
                            boolean forWebSocket){
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.transmitter = new Transmitter(client, call);
    return call;
  }

/** 实际上调用的构造函数 */
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    final EventListener.Factory eventListenerFactory = client.eventListenerFactory();
    // 传入的OkHttpClient对象
    this.client = client;
    // 传入的Request请求对象
    this.originalRequest = originalRequest;
    // 是否是webSocket请求,默认false
    this.forWebSocket = forWebSocket;
    // 一个可以从故障中恢复的拦截器
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
  }

2.4.4 RealCall.execute()

/** execute@RealCall.class */
/** 同步网络请求 */
@Override 
public Response execute() throws IOException {
    // 1.当前请求已经执行过 抛异常
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    // 2.跟踪超时等运行时数据
    transmitter.timeoutEnter();
    transmitter.callStart();
    try {
      // 3.执行同步网络请求操作
      client.dispatcher().executed(this);
      // 4.返回结果
      return getResponseWithInterceptorChain();
    } finally {
      // 5.结束当前网络请求
      client.dispatcher().finished(this);
    }
  }

/** getResponseWithInterceptorChain@RealCall.class */
/** 执行网络请求,并返回结果 */
Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    // 建立一个完整的拦截器堆栈
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
  	// 1.重试与重定向拦截器
    interceptors.add(new RetryAndFollowUpInterceptor(client));
  	// 2.桥接拦截器
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
  	// 3.请求是从内部缓存中发出,缓存拦截器将返回写入到响应缓存中和此请求对应
    interceptors.add(new CacheInterceptor(client.internalCache()));
    // 4.打开客户端与目标服务器的连接-->连接服务器
    interceptors.add(new ConnectInterceptor(client));
  
    
    if (!forWebSocket) {
      // 5.如果不是WebSocket长链接,添加网络拦截器
      interceptors.addAll(client.networkInterceptors());
    }
  	// 6.拦截器链中最后一个拦截器,对服务器进行请求呼叫
    interceptors.add(new CallServerInterceptor(forWebSocket));

    // 7.创建拦截器链的实例
    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);
      }
    }
  }

2.4.5 RealInterceptorChain.proceed()

/** proceed@RealInterceptorChain.class */
/** 执行网络请求,并返回结果 */
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.
    // 递归调用,返回Response
  	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;
  }

2.4.6 Dispatcher

对于很多异步请求,请求的执行顺序,执行规则均由分发器决定的,每个分发器的内部有个ThreadPoolExecutor,这是线程池的核心类,其主要作用是将线程进行复用,每个请求需要一个线程去执行,每次都重新创建新的线程太消耗性能,因此对于有已经执行完上一个任务的线程进行复用,不需要再重新创建一个新的线程去执行下一个任务。

Dispatcher内部主要方法:

/** Dispatch.class */

/** 
每一个请求都创建了一个RealCall实例,异步请求AsyncCall是RealCall的内部类;
每个Call都需要一个线程去任务,执行Call的过程其实就是执行线程的excute()过程。
当Dispatcher接收到一个请求时,Dispatcher负责在其内部维护的线程池中找出空闲的线程去执行其execute()方法。
*/

/** 主要变量 */
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
/** Executes calls. Created lazily. */
private @Nullable ExecutorService executorService;

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

/** 连接池 */
public synchronized ExecutorService executorService() {
    if (executorService == null) {
      // 本质上是ThreadPoolExecutor
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

/**  ==================  同步   =================== */
synchronized void executed(RealCall call) {
   runningSyncCalls.add(call);
}

/**  ==================  异步   =================== */
void enqueue(AsyncCall call) {
    synchronized (this) {
      // 直接加入到等待队列
      readyAsyncCalls.add(call);

      // Mutate the AsyncCall so that it shares the AtomicInteger of an existing 
      // running call to the same host.
      // 如果不是WebSocket长链接
      if (!call.get().forWebSocket) {
        // 判断当前call的host是否可以用执行中的某个call的host复用
        AsyncCall existingCall = findExistingCallWithHost(call.host());
        // 复用host
        if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
      }
    }
    // 执行网络请求
    promoteAndExecute();
  }

/** 判断当前的网络请求的host在 当前正在进行的 网络请求队列中是否已存在 */
@Nullable 
private AsyncCall findExistingCallWithHost(String host) {
    for (AsyncCall existingCall : runningAsyncCalls) {
      if (existingCall.host().equals(host)) return existingCall;
    }
    for (AsyncCall existingCall : readyAsyncCalls) {
      if (existingCall.host().equals(host)) return existingCall;
    }
    return null;
  }

/** 执行网络请求 */
private boolean promoteAndExecute() {
    assert (!Thread.holdsLock(this));

    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
      for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall asyncCall = i.next();
				// Max capacity.
        if (runningAsyncCalls.size() >= maxRequests) break; 
        // Host max capacity.
        if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; 
        i.remove();
        asyncCall.callsPerHost().incrementAndGet();
        executableCalls.add(asyncCall);
        runningAsyncCalls.add(asyncCall);
      }
      isRunning = runningCallsCount() > 0;
    }

  	// 执行
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      asyncCall.executeOn(executorService());
    }

    return isRunning;
  }
/** RealCall请求执行结束后调用 */
/** Used by {@code Call#execute} to signal completion. */
  void finished(RealCall call) {
    finished(runningSyncCalls, call);
  }

  private <T> void finished(Deque<T> calls, T call) {
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      idleCallback = this.idleCallback;
    }

    boolean isRunning = promoteAndExecute();

    if (!isRunning && idleCallback != null) {
      idleCallback.run();
    }
  }

Dispatcher总结:

(1)runningAsyncCalls存放正在执行的请求,readyAsyncCalls存放等待执行的请求;

(2)该类中有一个newCachedThreadPool线程执行器,利用该执行器来执行异步请求的execute方法。也就是说异步请求发送在非当前工作线程,即创建异步请求的线程,而是从线程池中获取一条线程执行网络请求。同步请求则直接是在当前工作线程中执行。

(3)该类对异步请求的管理是通过maxRequests、maxRequestsPerHost进行控制的,前者控制线程池中同时运行的最大请求数,防止同时运行线程过多,造成OOM。后者限制了同一hostname下的请求数,防止一个应用占用的网络资源过多,优化用户体验。

2.4.7 Response

Response.class

/** Response.class 主要变量与方法 */
private final Request request;  //对应的request  
private final Protocol protocol; //对应的Http协议  
private final int code; //返回状态码  
private final String message; //Http状态对应的消息  
private final Handshake handshake; //TLS握手协议Transport Layer Security  
private final Headers headers; //返回响应头  
private final ResponseBody body; //Http表单  
private Response networkResponse; //来源于网络的Response,如果响应来自缓存,则该值为null  
private Response cacheResponse; //来自缓存的响应  
private final Response priorResponse;  //在redirect或者授权改变的时候,该结果不为空  
private volatile CacheControl cacheControl; // Lazily initialized.  

@Override public String toString() {
    return "Response{protocol="
        + protocol
        + ", code="
        + code
        + ", message="
        + message
        + ", url="
        + request.url()
        + '}';
  }

/** Returns the HTTP status code. */
  public int code() {
    return code;
  }

/**
   * Returns true if the code is in [200..300), which means the request was successfully 
   * received, understood, and accepted.
   */
  public boolean isSuccessful() {
    return code >= 200 && code < 300;
  }

/** Returns the HTTP status message. */
  public String message() {
    return message;
  }

/**
   * Returns a non-null value if this response was passed to {@link Callback#onResponse} or 
   * returned from {@link Call#execute()}. Response bodies must be {@linkplain ResponseBody 
   * closed} and may be consumed only once.
   *
   * <p>This always returns null on responses returned from {@link #cacheResponse}, {@link
   * #networkResponse}, and {@link #priorResponse()}.
   */
  public @Nullable ResponseBody body() {
    return body;
  }

ResponseBody.class

/** ResponseBody.class 主要变量与方法 */

/** Multiple calls to {@link #charStream()} must return the same instance. */
  private @Nullable Reader reader;

  public abstract @Nullable MediaType contentType();

  /**
   * Returns the number of bytes in that will returned by {@link #bytes}, 
   * or {@link #byteStream}, or -1 if unknown.
   */
  public abstract long contentLength();

	public abstract BufferedSource source();

  /** 输入流 */
  public final InputStream byteStream() {
    return source().inputStream();
  }

/**
   * Returns the response as a string.
   *
   * <p>If the response starts with a 
   * <a href="https://en.wikipedia.org/wiki/Byte_order_mark">Byte Order Mark (BOM)</a>, 
   * it is consumed and used to determine the charset of the response bytes.
   *
   * <p>Otherwise if the response has a Content-Type header that specifies a charset, 
   * that is used to determine the charset of the response bytes.
   *
   * <p>Otherwise the response bytes are decoded as UTF-8.
   *
   * <p>This method loads entire response body into memory. If the response body is very large 
   * this may trigger an {@link OutOfMemoryError}. Prefer to stream the response body if this 
   * is a possibility for your response.
   */
  public final String string() throws IOException {
    try (BufferedSource source = source()) {
      Charset charset = Util.bomAwareCharset(source, charset());
      return source.readString(charset);
    }
  }

注意事项:

1、Response.code是http响应行中的code,如果访问成功则返回200.这个不是服务器设置的,而是http协议中自带的。res中的code才是服务器设置的。注意二者的区别。

2、response.body().string()本质是输入流的读操作,所以它还是网络请求的一部分,所以这行代码必须放在子线程

3、response.body().string()只能调用一次,在第一次时有返回值,第二次再调用时将会返回null。原因是:response.body().string()的本质是输入流的读操作,必须有服务器的输出流的写操作时客户端的读操作才能得到数据。而服务器的写操作只执行一次,所以客户端的读操作也只能执行一次,第二次将返回null。

 

三、主要参考


参考链接(1):https://github.com/square/okhttp

参考链接(2):https://blog.csdn.net/qq_17470165/article/details/80543537

参考链接(3):https://blog.csdn.net/suyimin2010/article/details/80196443

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值