OkHttp是一个高效的网络请求框架,是square公司出品,同时也是目前android市场最为流行的框架,其核心主要有路由、连接协议、拦截器、代理、安全性认证、连接池以及网络适配。它是一款相对来说比较纯粹的网络框架,也正是这样的纯粹让它有了更好的扩展性和兼容性,可以跟多种上层框架进行结合封装,如Volley,Retrofit,HttpUrlConnection等。下面我们就具体聊聊它吧!
一、优缺点以及特性:
优点:
- 支持SPDY和Http2.0(Http2.0是SPDY的升级版,二者还是有一点差别);
- 链路复用,就是指连接同一主机的网络请求可以共用同一Socket,并且拥有自动维护的socket连接池,节省连接握手开销;
- 使用透明的Gzip压缩传输,减少流量开销;
- 使用响应缓存有效地避免了短时间内的重复请求;
- 多IP自动重连,当你的应用内有多个IP时,如果连接某个IP失败,OkHttp会自动切换到其他IP进行请求尝试;
缺点:
- 主要是请求发生在子线程,响应的结果没有切换到主线程,对于android开发的熟手来说,这点无伤大雅,很容易进行封装解决;
特性:
- 可配置拦截器,以便实现自己想要的业务需求;
- 可配置自定义Dispatcher,自己管理和维护线程的调度;
- 可配置自定义ConnectionPool;
- 支持基于Headers的缓存策略,可设置是否使用缓存,可设置缓存时长;
- 完美的SSL支持;
- 可设置代理;
- 灵活的超时设置;
- 灵活的header配置方式;
- 默认的重试机制,可更改重试次数;
- 封装完善的多种Method支持,如get,post,put,delete等;
- 完美支持大文件上传,多文件上传;
- 可取消网络请求;
- 支持同步和异步;
- 支持从常用的连接问题中自动恢复,还处理了代理服务器问题和SSL握手失败问题;
- API链式调用,方便开发者;
二、OkHttp的类
OkHttpClient
OkHttpClient官方的描述是:
Factory for calls, which can be used to send HTTP requests and read their responses.
- 从对外这个方面来理解,这个类是OkHttp对外的入口,其他地方想使用OkHttp这个库,你就饶不开这个类。
- 从对内这个方面来说,这个类是包括OkHttp这个库的众多属性,对众多属性进行初始化和封装的一个类。
- 从类的基础构造方面来说,这个类是通过Builder模式+外观模式进行构建的。
我们来看看该类包括了什么属性:
final Dispatcher dispatcher;//调度器
final @Nullable Proxy proxy;//代理
final List<Protocol> protocols;//协议
final List<ConnectionSpec> connectionSpecs;//传输层版本和连接协议
final List<Interceptor> interceptors;//拦截器
final List<Interceptor> networkInterceptors;//网络拦截器
final EventListener.Factory eventListenerFactory;
final ProxySelector proxySelector;//代理选择器
final CookieJar cookieJar;//cookie
final @Nullable Cache cache;//cache 缓存
final @Nullable InternalCache internalCache;//内部缓存
final SocketFactory socketFactory;//socket 工厂
final @Nullable SSLSocketFactory sslSocketFactory;//安全套层socket工厂 用于https
final @Nullable CertificateChainCleaner certificateChainCleaner;//验证确认响应书,适用HTTPS 请求连接的主机名
final HostnameVerifier hostnameVerifier;//主机名字确认
final CertificatePinner certificatePinner;//证书链
final Authenticator proxyAuthenticator;//代理身份验证
final Authenticator authenticator;//本地身份验证
final ConnectionPool connectionPool;//链接池 复用连接
final Dns dns;//域名
final boolean followSslRedirects;//安全套接层重定向
final boolean followRedirects;//本地重定向
final boolean retryOnConnectionFailure;//重试连接失败
final int connectTimeout;//连接超时
final int readTimeout;//读取超时
final int writeTimeout;//写入超时
类的构造方法:
public的
public OkHttpClient() {
this(new Builder());
}
和friendly的
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的构造方法:
public的
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;
}
和friendly的
Builder(OkHttpClient okHttpClient) {
this.dispatcher = okHttpClient.dispatcher;
this.proxy = okHttpClient.proxy;
this.protocols = okHttpClient.protocols;
this.connectionSpecs = okHttpClient.connectionSpecs;
this.interceptors.addAll(okHttpClient.interceptors);
this.networkInterceptors.addAll(okHttpClient.networkInterceptors);
this.eventListenerFactory = okHttpClient.eventListenerFactory;
this.proxySelector = okHttpClient.proxySelector;
this.cookieJar = okHttpClient.cookieJar;
this.internalCache = okHttpClient.internalCache;
this.cache = okHttpClient.cache;
this.socketFactory = okHttpClient.socketFactory;
this.sslSocketFactory = okHttpClient.sslSocketFactory;
this.certificateChainCleaner = okHttpClient.certificateChainCleaner;
this.hostnameVerifier = okHttpClient.hostnameVerifier;
this.certificatePinner = okHttpClient.certificatePinner;
this.proxyAuthenticator = okHttpClient.proxyAuthenticator;
this.authenticator = okHttpClient.authenticator;
this.connectionPool = okHttpClient.connectionPool;
this.dns = okHttpClient.dns;
this.followSslRedirects = okHttpClient.followSslRedirects;
this.followRedirects = okHttpClient.followRedirects;
this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure;
this.callTimeout = okHttpClient.callTimeout;
this.connectTimeout = okHttpClient.connectTimeout;
this.readTimeout = okHttpClient.readTimeout;
this.writeTimeout = okHttpClient.writeTimeout;
this.pingInterval = okHttpClient.pingInterval;
}
从上面的代码里,我们可以发现这2个类可以作为参数互相传到对方的构造方法里,这个跟我们一般标准的Builder模式不太一样,那这里为什么要这样做呢?OK,我们再来看一段官方对OkHttpClient这个类的另外一段描述:
Customize your client with newBuilder()
You can customize a shared OkHttpClient instance with newBuilder(). This builds a client that shares the same connection pool, thread pools, and configuration. Use the builder methods to configure the derived client for a specific purpose.
This example shows a call with a short 500 millisecond timeout:
OkHttpClient eagerClient = client.newBuilder() .readTimeout(500, TimeUnit.MILLISECONDS) .build();
Response response = eagerClient.newCall(request).execute();
从这段描述中我们可以看到,我们可以通过newBuilder()这个方法获取到一个shared OkHttpClient 实例,这个实例拥有和你刚才的OkHttpClient 对象一模一样的各种属性(想想为什么不用clone或者序列化呢?),我们看一下newBuilder()的代码
public Builder newBuilder() {
return new Builder(this);
}
该方法调用Builder的传入了当前的OkHttpClient对象的构造方法;而当我们初始化一个OkHttpClient时,会在其构造方法里传入一个Builder的对象,由此可见这2个类作为参数相互传到对方的构造方法里,其目的就是为了可以从一个对象拿到另外一个对象的全部属性。可是为什么要这样做呢?当你真正使用起来时,你会发现这样的代码设计会让你随性所欲地使用OkHttpClient的各个参数,方便使用者自定义等,说白了,扩展性强。
这个类中的大部分成员方法都是链式set属性值的方法,只有少部分方法比较特殊,其中一个就是:
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
这个方法,是OkHttp网络请求的发动的入口,同时也承载着请求结果的接收。看个代码:
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.url("http://www.weather.com.cn/data/sk/101110101.html")
.build();
okhttp3.Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println("call is:" + call);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
ResponseBody responseBody = response.body();
String bodyString = responseBody.string();
System.out.println("bodyString is:" + bodyString);
}
});
okHttpClient.newCall(request)初始化一个Call对象,call.enqueue(new Callback() )发起一个异步请求并得到异步回调的数据,所有的这些都依赖于这个Call对象,所以初始化Call是必然。截止这里,一个简单的网络请求完成,我们再来聊聊这里涉及到的其他类。
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 {
/** Returns the original request that initiated this call. */
Request request();//获取初始化时的请求实例
/**
* Invokes the request immediately, and blocks until the response can be processed or is in
* error.
*
* <p>To avoid leaking resources callers should close the {@link Response} which in turn will
* close the underlying {@link ResponseBody}.
*
* <pre>{@code
*
* // ensure the response (and underlying response body) is closed
* try (Response response = client.newCall(request).execute()) {
* ...
* }
*
* }</pre>
*
* <p>The caller may read the response body with the response's {@link Response#body} method. To
* avoid leaking resources callers must {@linkplain ResponseBody close the response body} or the
* Response.
*
* <p>Note that transport-layer success (receiving a HTTP response code, headers and body) does
* not necessarily indicate application-layer success: {@code response} may still indicate an
* unhappy HTTP response code like 404 or 500.
*
* @throws IOException if the request could not be executed due to cancellation, a connectivity
* problem or timeout. Because networks can fail during an exchange, it is possible that the
* remote server accepted the request before the failure.
* @throws IllegalStateException when the call has already been executed.
*/
Response execute() throws IOException;//同步执行网络请求
/**
* Schedules the request to be executed at some point in the future.
*
* <p>The {@link OkHttpClient#dispatcher dispatcher} defines when the request will run: usually
* immediately unless there are several other requests currently being executed.
*
* <p>This client will later call back {@code responseCallback} with either an HTTP response or a
* failure exception.
*
* @throws IllegalStateException when the call has already been executed.
*/
void enqueue(Callback responseCallback);//异步执行网络请求
/** Cancels the request, if possible. Requests that are already complete cannot be canceled. */
void cancel();//取消网络请求
/**
* Returns true if this call has been either {@linkplain #execute() executed} or {@linkplain
* #enqueue(Callback) enqueued}. It is an error to execute a call more than once.
*/
boolean isExecuted();//某个请求是否正在执行
boolean isCanceled();//某个请求是否已经取消
/**
* Returns a timeout that spans the entire call: resolving DNS, connecting, writing the request
* body, server processing, and reading the response body. If the call requires redirects or
* retries all must complete within one timeout period.
*
* <p>Configure the client's default timeout with {@link OkHttpClient.Builder#callTimeout}.
*/
Timeout timeout();
/**
* Create a new, identical call to this one which can be enqueued or executed even if this call
* has already been.
*/
Call clone();
interface Factory {
Call newCall(Request request);
}
}
所有涉及到它的方法具体执行的肯定都是这个接口的实现者,例如上文中call.enqueue()中call的实现类就是RealCall。
RealCall
RealCall持有的对象:
final class RealCall implements Call {
final OkHttpClient client;
final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
final AsyncTimeout timeout;
/**
* There is a cycle between the {@link Call} and {@link EventListener} that makes this awkward.
* This will be set after we create the call instance then create the event listener instance.
*/
private @Nullable EventListener eventListener;
/** The application's original request unadulterated by redirects or auth headers. */
final Request originalRequest;
final boolean forWebSocket;
// Guarded by this.
private boolean executed;
...
RealCall的构造方法(一个private的,一个static的):
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
this.timeout = new AsyncTimeout() {
@Override protected void timedOut() {
cancel();
}
};
this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
}
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.eventListener = client.eventListenerFactory().create(call);
return call;
}
我们知道OkHttpClient会持有涉及到网络请求的众多参数,所以在整个网络请求过程中,有很多的类都会持有OkHttpClient的对象,以便更改或设置一些属性的值,当然,RealCall也不例外,它也持有OkHttpClient的对象,在RealCall里有以下地方会用到OkHttpClient对象:
62 this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
68 this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
74 call.eventListener = client.eventListenerFactory().create(call);
91 client.dispatcher().executed(this);
...
100 client.dispatcher().finished(this);
...
126 client.dispatcher().enqueue(new AsyncCall(responseCallback));
...
145 @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
146 @Override public RealCall clone() {
147 return RealCall.newRealCall(client, originalRequest, forWebSocket);
148 }
...
179 assert (!Thread.holdsLock(client.dispatcher()));
...
191 client.dispatcher().finished(this); // This call is no longer running!
...
218 client.dispatcher().finished(this);
...
237 Response getResponseWithInterceptorChain() throws IOException {
238 // Build a full stack of interceptors.
239 List<Interceptor> interceptors = new ArrayList<>();
240 interceptors.addAll(client.interceptors());
241 interceptors.add(retryAndFollowUpInterceptor);
242 interceptors.add(new BridgeInterceptor(client.cookieJar()));
243 interceptors.add(new CacheInterceptor(client.internalCache()));
244 interceptors.add(new ConnectInterceptor(client));
245 if (!forWebSocket) {
246 interceptors.addAll(client.networkInterceptors());
247 }
248 interceptors.add(new CallServerInterceptor(forWebSocket));
249
250 Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
251 originalRequest, this, eventListener, client.connectTimeoutMillis(),
252 client.readTimeoutMillis(), client.writeTimeoutMillis());
253
254 return chain.proceed(originalRequest);
255 }
RealCall还会持有一个Request的对象,这个不难理解,从名字上看,Request就是网络请求的参数,RealCall会通过execute()或者enqueue(Callback responseCallback)方法进行网络请求,自然会用到Request这个对象。
另外,RealCall还会持有Dispatcher的一个对象,Dispatcher简单地说就是执行异步请求时的调度器,也就是说网络请求会进入这个类进行调度,具体的后面还会做介绍。
RealCall还有一个特别特别重要的方法,就是上文中已经提到的
237 Response getResponseWithInterceptorChain() throws IOException {
...
254 return chain.proceed(originalRequest);
255 }
这个方法包含了OkHttp整个架构设计的精髓,后面会具体说到。
AsyncCall
AsyncCall是RealCall的内部类,会持有RealCall的属性和方法,主要用于异步请求,当它执行网络请求时会直接调用外部类的属性以及方法,它extends NamedRunnable,我们看一下NamedRunnable这个类,很简单:
**
* Runnable implementation which always sets its thread name.
*/
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
该类implements了Runnable,有个abstract 的execute()方法,run()会执行execute(),该方法由NamedRunnable 的子类具体实现,所以我们先来看一下AsyncCall的execute()方法。
@Override protected void execute() {
boolean signalledCallback = false;
timeout.enter();
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
e = timeoutExit(e);
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
核心的是一行:Response response = getResponseWithInterceptorChain();
,就是我们上文提出RealCall这个外部类的关键结构设计方法。
Dispatcher
是一个请求分发器,不管是同步还是异步的请求都会经过这个类进行分发,同时管理请求的等待,执行,取消。
这个类也是非常重要的,为什么呢?因为这个可以自定义,如果你能了解源码里的dispatch原理,对自定义dispatcher非常有益。
Policy on when async requests are executed.
Each dispatcher uses an ExecutorService to run calls internally. If you supply your own executor, it should be able to run the configured maximum number of calls concurrently.
这是官方对这个类的描述。我们看一下这个持有的属性和构造方法:
public final class Dispatcher {
private int maxRequests = 64;//最高并发数
private int maxRequestsPerHost = 5;//同一Host最高并发数
private @Nullable Runnable idleCallback;
/** 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 Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
...
readyAsyncCalls 是等待的异步线程的队列
runningAsyncCalls 是正在执行的异步线程队列
runningSyncCalls 是正在执行的同步请求队列
为什么用ArrayDeque呢?因为ArrayDeque实现了双端队列,内部使用循环数组实现,在两端添加、删除元素的效率很高,动态扩展需要的内存分配以及数组拷贝开销可以被平摊,具体来说,添加N个元素的效率为O(N)。虽然根据元素内容查找和删除的效率比较低,且没有索引,但是在这里我们也用不到,所以发挥了双端队列的优点。
maxRequests 是最高并发数,可设置。如果有超过了这个的限制,就将异步请求AsyncCall添加readyAsyncCalls(待执行的异步请求队列)去等待执行。
maxRequestsPerHost 是同一个Host的最高并发数,可设置。如果有超过了这个的限制,就将异步请求AsyncCall添加readyAsyncCalls(待执行的异步请求队列)去等待执行。
executorService是执行异步的线程池(同步并不会扔到这个线程池中执行),这个线程池也是可设置的。关于异步线程的所有执行其实是发生在这个线程池里,所以这个线程池是比较核心的,我们来看一下这个池:
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
初始化一个ThreadPoolExecutor对象,构造方法里传了6个参数,这6个参数分别对应:
- 参数0,代表核心线程的数量,即线程池中最少线程时的数量(当所有线程都空闲时),为0的话,说明线程空闲时,不保留任何线程,做到线程低占用。
- 参数Integer.MAX_VALUE,代表最大线程数,即线程池中最多线程时的数量,为Integer.MAX_VALUE的话,说明可以开启无限多的线程进行工作,线程工作完了再关闭。
- 参数60,和 参数TimeUnit.SECONDS,表示当线程池的数量比核心线程的数量大时,等待60秒之后就会去关闭空闲线程,使总的线程数量不会大于核心线程数量。
- 参数new SynchronousQueue<Runnable>(), 代表这个线程等待队列是同步队列,当有一个线程进来时,就同时会有一个线程出去,也就是说线程不会停留在其中,一进入就立马出去执行,这种方式在高频请求时是很合适的。
- 参数Util.threadFactory("OkHttp Dispatcher", false),表示提供一个线程工厂,用于创建新的线程。
线程池这样设计,是让你在需要的时候可以无限创建线程(Integer.MAX_VALUE个),不需要时不做保留,当空闲60秒后就会被自动回收,保证高阻塞,低占用。ThreadPoolExecutor是android sdk自带的,内部具体的实现可以看一下相关的源码,这里就不详细说明了。
promoteAndExecute()方法将符合条件的调用从ReadyAsyncCalls提升到runningAsyncCalls,并在Executor服务上运行它们,但是不能使用同步调用。
cancelAll()方法取消所有请求,包括所有同步请求,所有正在执行的异步请求,所有等待执行的异步请求。
Request、Response和Headers
Request作为请求信息的封装,内部包含了请求url,请求方法method,请求头headers,请求体RequestBody,tag标签等。
Response作为相应信息的封装,内部包含对应的请求信息request,http协议protocol,响应码code,响应头headers,响应消息message,响应体ResponseBody等。
Headers作为网络请求或者响应的头部信息的封装,内部也是通过Builder模式设计的,
请求Header主要包括的字段有:Accept,Accept-Charset,Accept-Encoding,Accept-Language,Authorization,Cache-Control,Cookie,Content-Length,Content-Type,Host,Proxy-Authorization,Range等;
响应Header主要包括的字段有:Accept-Ranges,Age,Cache-Control,Content-Encoding,Content-Language,Content-Length,Content-Location,Content-Range,Content-Type,Date,ETag,Expires,Last-Modified,Location,Refresh,Status,Server,Transfer-Encoding等;
关于OkHttp拦截器的内容可以查看:https://www.jianshu.com/p/211e8188d866
网友评论