OkHttp 是什么
OkHttp 是一个 Http 客户端, 和 Apache Httpclient 类似, 但底层网络连接封装不一样, OkHttp 使用的是 okio, Httpclient 直接使用底层 Socket 来封装网络连接, 更多细节后面再研究, 这里主要记录 OkHttp 的使用方法
提供了什么功能
这里直接截取了官网的介绍
- HTTP/2 support allows all requests to the same host to share a socket.
- Connection pooling reduces request latency (if HTTP/2 isn’t available).
- Transparent GZIP shrinks download sizes.
- Response caching avoids the network completely for repeat requests.
当然这里并非全部, 个人理解的是 连接池、异步、重试、异常处理等重要功能都有
核心对象介绍
Call
该接口代表一个可向发起请求的对象(使用内部持有的 OkHttpClient 发送请求),包含了 request/response 流,可以被 canceled,只能被执行一次
Request
代表 http 请求中的 request 对象,通过该对象封装请求数据,如:method、request header、url、request body 等
使用 Builder 建造者模式来封装请求
Request request = new Request.Builder()
.get()
.url("http://www.baidu.com")
.header("Accept", "application/json")
.build();
- get() 使用 GET 方法,同样的还有 post()、head()、put() 等
- url() 请求路径
- header() 添加请求头
OkHttpClient
创建 Call 对象的工厂,可以被用来发送 http 请求并解析返回的 response。
该对象应该在所有 http 调用者中共享,因为 OkHttpClient 对连接进行了缓存和复用,当所有 http 调用端共享该对象时,意味着同时共享了所有的 connection pool , 并且降低了延迟和内存开销。异步调用时,由于使用内部线程池来发送 http 请求,因此在异步调用过程中,共享 OkHttpClient 还共享了线程池
创建方式
- 使用默认配置
OkHttpClient okHttpClient = new OkHttpClient();
- 使用自定义配置
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(500, TimeUnit.MILLISECONDS)
.build();
- 使用 execute 同步发送 GET 请求
Request request = new Request.Builder()
.get()
.url("http://www.baidu.com")
.header("Accept", "application/json")
.build();
try {
Response response = okHttpClient.newCall(request).execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
- 使用 execute 同步发送 POST 请求
Request request = new Builder()
.url("")
// 设置 request header 或 response body 的 Content-Type 类型
.post(RequestBody.create(MediaType.parse("application/json;charset=utf-8"), json))
.build();
try {
Response response = okHttpClient.newCall(request).execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
- 使用 enqueue 异步发送 GET 请求
CountDownLatch latch = new CountDownLatch(1);
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.body().string());
latch.countDown();
}
});
latch.await();
Interceptor
Interceptor 为实现拦截器的标准接口,实现该接口之后,在 intercept(Chain chain) 中必须调用 chain.proceed(request) 方法,通过拦截器链模式来观察整个网络请求
如:用该拦截器来记录每次请求时间,并将超过 500 毫秒的请求记录下来
@Component
@Slf4j
public class TimeLogInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response response;
Request rq = chain.request();
long start = System.currentTimeMillis();
try {
response = chain.proceed(rq);
} catch (Exception e) {
log.error("error call request,cost>{},uri>{},e->{}", System.currentTimeMillis() - start,
rq.url(), e);
throw e;
} finally {
long end = System.currentTimeMillis();
long cost = end - start;
if (cost > 500) {
log.warn("RestTemplate cost time exceed={} ms,uri={}", cost, rq.url());
}
}
return response;
}
可通过 addInterceptor 或者 addNetworkInterceptor 添加,addInterceptor 添加的为全局拦截器,addNetworkInterceptor 添加的为网络拦截器,区别是:addInterceptor 只会调用一次,addNetworkInterceptor 随着网络请求的次数变化,如:当发生请求重试时,此时内部的拦截器将对 addNetworkInterceptor 中添加的拦截器进行多次调用
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(500, TimeUnit.MILLISECONDS)
.addInterceptor(xxx)
.addNetworkInterceptor(xx)
.build();
ConnectionPool
该类用来管理 HTTP 和 HTTP/2 复用的连接,以便降低网络延迟。HTTP 请求通过同一请求地址来共用连接
ConnectionPool connectionPool = new ConnectionPool(100, 1, TimeUnit.MINUTES);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(500, TimeUnit.MILLISECONDS)
.connectionPool(connectionPool)
.build();
构造方法接受 3 个参数,分别代表,最大闲置连接、最长闲置时间、闲置时间单位,默认的是最多 5 个连接,最长保持 5 分钟,关于如何设置闲置时间,需要根据被调用端的 KeepAlive 的时间
网友评论