由Square公司贡献的一个处理网络请求的开源项目,是目前Android使用最广泛的网络框架。从Android4.4开始 HttpURLConnection的底层实现采用的是OkHttp。
特点:
1、支持HTPP/2并允许对同一主机的所有请求共享套接字
2、如果非HTTP/2,则通过连接池减少请求延迟
3、默认请求GZip压缩数据
4、响应缓存,避免了重复请求的网络
使用方法:
private static void get(String url,OkHttpClient client) throws IOException {
Request request = new Request.Builder()
.url(url).build();
//同步请求
Call call = client.newCall(request);
Response response = call.execute();
//获取响应
ResponseBody body = response.body();
System.out.println(body.toString());
}
private static void post(String url,OkHttpClient client){
RequestBody requestBody = new FormBody.Builder().add("name","111")
.add("age","11").build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
// 执行异步请求
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.toString());
}
});
}
OkHttp请求过程中最少只需要接触OkHttpClient、Request、Call、 Response,但是框架内部进行大量的逻辑处理。而且通过HttpClient可以看出是用的Builder设计模式。
分发器:
1、同步分发
同步分发只有一个running的同步队列,分发器只记录请求,用于判断IdleRunnable是否需要执行
2、异步请求,有一个ready执行的队列和一个running队列,这两个队列是如何处理工作的呢
1)对于符合条件的call是什么条件呢,我们应该是放入running队列还是ready队列?
. running队列中任务不能大于64
. 同一域名主机的请求不能大于5
满足上面两个条件就放入running队列,否则放入ready队列。
2)从ready队列移动到running队列
遍历ready队列,假如1)的两个条件都满足,则从ready中移出call,添加到running队列
3)分发器的线程
这个线程池有点意思,我们看参数:
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;
}
核心线程数=0、最大线程数=Integer.MAX_VALUE、任务队列使用的是SynchronousQueue队列 ,这是一个不存储元素的阻塞队列,就这个保证了任务执行无需等待,符合我们的网络请求场景。
拦截器:
在请求需要执行时,通过getResponseWithInterceptorChain()获得请求的结果Response
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
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, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
首先,拦截器采用的是责任链设计模式
客户只需要将请求发送到责任链上即可,无须关心请求的处理细节个请求传递;这样责任链就将请求的发送者和处理者解耦了。
重试重定向拦截器:
重定向: followUpRequest(response, streamAllocation.route())重新返回一个经过重定向的Request。并且重定向的次数不能大于20次
桥接拦截器:
其实就是补全请求头
缓存拦截器:
缓存规则:http的缓存我们可以按照行为将它们分为强缓存、协商缓存
1、强缓存:表示浏览器不会将请求发送给服务器,直接从缓存中取,利用http的返回头中的Expires或者Cache-Control两个字段来控制,用来表示资源的缓存时间。
2、协商缓存:表示浏览器会将请求发送到服务器,服务器告诉浏览器可以从缓存中获取响应。响应码返回304。
缓存策略:
拦截器通过CacheStrategy判断使用缓存或发起网络请求。此对象中的networkRequest与cacheResponse分别代表需要发起请求或者直接使用缓存。
networkRequest | cacheResponse | 说明 |
Null | Not Null | 直接使用缓存 |
Not Null | Null | 向服务器发起请求 |
Null | Null | 要求使用缓存,但是没有缓存。直接gg,okhttp直接返回504 |
Not Null | Not Null | 发起请求,若得到响应为304(无修改),则更新缓存响应并返回 |
即:networkRequest存在则优先发起网络请求,否则使用cacheResponse缓存,若都不存在则请求失败!
连接拦截器:
请求服务拦截器:
Expect:100-continue
一般出现于上传大容量请求体或者需要验证。代表了先询问服务器是否原因接 收发送请求体数据,
OkHttp的做法:
如果服务器允许则返回100,客户端继续发送请求体;
如果服务器不允许则直接返回给用户。
同时服务器也可能会忽略此请求头,一直无法读取应答,此时抛出超时异常