OKHTTP 要点

官网文档

简单示例

  • GET

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class demo {
    OkHttpClient client = new OkHttpClient();

    String run(String url) throws IOException {
    Request request = new Request.Builder()
    .url(url)
    .build();

    try (Response response = client.newCall(request).execute()) {
    return response.body().string();
    }
    }
    }
  • POST

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    class demo {

    public static final MediaType JSON
    = MediaType.get("application/json; charset=utf-8");

    OkHttpClient client = new OkHttpClient();

    String post(String url, String json) throws IOException {
    RequestBody body = RequestBody.create(json, JSON);
    Request request = new Request.Builder()
    .url(url)
    .post(body)
    .build();
    try (Response response = client.newCall(request).execute()) {
    return response.body().string();
    }
    }
    }

复杂示例

拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

class LoggingInterceptor implements Interceptor {

@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();

long t1 = System.nanoTime();
logger.info(String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));

Response response = chain.proceed(request);

long t2 = System.nanoTime();
logger.info(String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));

return response;
}
}

事件通知器

  • 事件通知器、对网络请求过程任意阶段进行兴趣订阅
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31


class PrintingEventListener extends EventListener {
private long callStartNanos;

private void printEvent(String name) {
long nowNanos = System.nanoTime();
if (name.equals("callStart")) {
callStartNanos = nowNanos;
}
long elapsedNanos = nowNanos - callStartNanos;
System.out.printf("%.3f %s%n", elapsedNanos / 1000000000d, name);
}

@Override public void callStart(Call call) {
printEvent("callStart");
}

@Override public void callEnd(Call call) {
printEvent("callEnd");
}

@Override public void dnsStart(Call call, String domainName) {
printEvent("dnsStart");
}

@Override public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {
printEvent("dnsEnd");
}
///...
}
  • events

    缓存

  • 根据响应头部对文件的 lastModify标识 + 缓存有效时间 判断 当前文件再当前时间是否过期

1
2
3
4
5
6
7
8
9


private val client: OkHttpClient = OkHttpClient.Builder()
.cache(Cache(
directory = File(application.cacheDir, "http_cache"),
// $0.05 worth of phone storage in 2020
maxSize = 50L * 1024L * 1024L // 10 MiB
))
.build()

连接池配置

  • 连接池配置
  • 官方文档有说明、同一个URL 如果连接池中有连接、则直接拿连接请求、
    如果没有、则重新建立DNS TCP连接、所以可以配大些、以减少这些网络开销
1
2

ConnectionPool connectionPool = new ConnectionPool(15, 5L, TimeUnit.MINUTES);

其他:请求认证、HTTPS

1
2
3
4
5
6
7
8
9
10
11
12

.authenticator(new Authenticator() {
@Override public Request authenticate(Route route, Response response) throws IOException {
if (response.request().header("Authorization") != null) {
return null; // Give up, we've already attempted to authenticate.
}
String credential = Credentials.basic("jesse", "password1");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
})

维护client注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

method


@Bean(name = "httpClient")
@ConditionalOnMissingBean(name = { "OkHttpClient" })
OkHttpClient initHttpClient() {


ConnectionPool connectionPool = new ConnectionPool(30, 5L, TimeUnit.MINUTES);

return new OkHttpClient()
.newBuilder()
.retryOnConnectionFailure(true)
.connectionPool(connectionPool)
.eventListenerFactory(OKHttpListener.OKHttpListenerFACTORY)
.addNetworkInterceptor(new LoggerInterceptor())
.readTimeout(10, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build();

}