OkHttp 动态超时时间配置

思路

  • 自定义一个拦截器
  • 在拦截器中重置超时时间等配置

关键代码

HeadersEx.java

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package cn.tisson.common.okhttp.util;

import lombok.Getter;
import okhttp3.Headers;

/**
* @author YL
*/
public class HeadersEx {
private static final String NAME = HeadersEx.class.getSimpleName();
public static final String CONNECT_TIMEOUT = NAME + ".connectTimeout";
public static final String WRITE_TIMEOUT = NAME + ".writeTimeout";
public static final String READ_TIMEOUT = NAME + ".readTimeout";
public static final String PRINT_LOG = NAME + ".printLog";

@Getter
private final Integer connectTimeout;
@Getter
private final Integer writeTimeout;
@Getter
private final Integer readTimeout;
@Getter
private final boolean printLog;

private HeadersEx(Integer connectTimeout, Integer writeTimeout, Integer readTimeout, boolean printLog) {
super();
this.connectTimeout = connectTimeout;
this.writeTimeout = writeTimeout;
this.readTimeout = readTimeout;
this.printLog = printLog;
}

public static HeadersEx.Builder defaultConfig() {
return new Builder();
}

public static final class Builder {
private Integer connectTimeout;
private Integer writeTimeout;
private Integer readTimeout;
private boolean printLog = true;

Builder() {
}

/**
* 配置 connectTimeout,单位:ms
*
* @param connectTimeout 链接超时时间
*/
public Builder connectTimeout(Integer connectTimeout) {
this.connectTimeout = connectTimeout;
return this;
}

/**
* 配置 writeTimeout,单位:ms
*
* @param writeTimeout 请求超时时间
*/
public Builder writeTimeout(Integer writeTimeout) {
this.writeTimeout = writeTimeout;
return this;
}

/**
* 配置 readTimeout,单位:ms
*
* @param readTimeout 响应超时时间
*/
public Builder readTimeout(Integer readTimeout) {
this.readTimeout = readTimeout;
return this;
}

/**
* 配置日志打印开关
*
* @param printLog 是否打印request body、response body等日志
*/
public Builder printLog(boolean printLog) {
this.printLog = printLog;
return this;
}

HeadersEx build() {
return new HeadersEx(this.connectTimeout, this.writeTimeout, this.readTimeout, this.printLog);
}
}

/**
* 配置读取超时时间
*
* @param builder 响应超时时间:s
*/
public static Headers of(HeadersEx.Builder builder) {
HeadersEx build = builder.build();
Integer connectTimeout = build.getConnectTimeout();
Integer writeTimeout = build.getWriteTimeout();
Integer readTimeout = build.getReadTimeout();
boolean printLog = build.isPrintLog();
return Headers.of(
CONNECT_TIMEOUT, connectTimeout == null ? "" : String.valueOf(connectTimeout.intValue()),
WRITE_TIMEOUT, writeTimeout == null ? "" : String.valueOf(writeTimeout.intValue()),
READ_TIMEOUT, readTimeout == null ? "" : String.valueOf(readTimeout.intValue()),
PRINT_LOG, String.valueOf(printLog)
);
}
}

TimeoutInterceptor.java

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package cn.tisson.common.okhttp.interceptor;

import cn.tisson.common.okhttp.util.HeadersEx;
import cn.tisson.common.util.StrUtils;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
* 动态配置 connectTimeout、writeTimeout、readTimeout 超时时间拦截器
*
* @author YL
*/
@Slf4j
public class TimeoutInterceptor implements Interceptor {

@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String connectTimeout = request.header(HeadersEx.CONNECT_TIMEOUT);
if (StrUtils.isNotBlank(connectTimeout)) {
// 动态修改:连接超时时间
chain = chain.withConnectTimeout(Integer.parseInt(connectTimeout), TimeUnit.MILLISECONDS);
}
String writeTimeout = request.header(HeadersEx.WRITE_TIMEOUT);
if (StrUtils.isNotBlank(writeTimeout)) {
// 动态修改:请求超时时间
chain = chain.withWriteTimeout(Integer.parseInt(writeTimeout), TimeUnit.MILLISECONDS);
}

String readTimeout = request.header(HeadersEx.READ_TIMEOUT);
if (StrUtils.isNotBlank(readTimeout)) {
// 动态修改:响应超时时间
chain = chain.withReadTimeout(Integer.parseInt(readTimeout), TimeUnit.MILLISECONDS);
}
// log.info("connectTimeoutMillis: {}", chain.connectTimeoutMillis());
// log.info("writeTimeoutMillis: {}", chain.writeTimeoutMillis());
// log.info("readTimeoutMillis: {}", chain.readTimeoutMillis());
return chain.proceed(request);
}
}

OkHttpTest.java

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
private OkHttpClient okHttpClient() {
OkHttpCommonProperties props = properties.getCommon();

long connectTimeout = props.getConnectTimeout().toMillis();
long readTimeout = props.getReadTimeout().toMillis();
long writeTimeout = props.getWriteTimeout().toMillis();

int maxIdleConnections = props.getPool().getMaxIdleConnections();
long keepAliveDuration = props.getPool().getKeepAliveDuration().toMillis();

OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS);
builder.readTimeout(readTimeout, TimeUnit.MILLISECONDS);
builder.writeTimeout(writeTimeout, TimeUnit.MILLISECONDS);

builder.retryOnConnectionFailure(false);
// 配置连接池
ConnectionPool pool = new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.MILLISECONDS);
builder.connectionPool(pool);

// 添加动态超时时间配置拦截器
builder.addInterceptor(new TimeoutInterceptor());
// 添加日志拦截器
// builder.addInterceptor(new LoggingInterceptor());
try {
// 添加 https 支持
SSLContext sc = SSLContext.getInstance("SSL");
// SSLContext sc = SSLContext.getInstance("TLS");
DisabledValidationTrustManager trustManager = new DisabledValidationTrustManager();
sc.init(null,
new TrustManager[]{trustManager},
new java.security.SecureRandom());
builder.sslSocketFactory(sc.getSocketFactory(), trustManager);
builder.hostnameVerifier(NoopHostnameVerifier.INSTANCE);
} catch (NoSuchAlgorithmException | KeyManagementException e) {
log.error("okhttp init TLS failed.");
}
return builder.build();
}


@Test
public void okHttpClient() throws OkHttpException {
OkHttpClient client = okHttpClient();

HeadersEx.Builder builder = HeadersEx.defaultConfig()
.connectTimeout(4000)
.readTimeout(10000);
Request.Builder requestBuilder = new Request.Builder()
.url(url)
.headers(HeadersEx.of(builder));
Request request = requestBuilder.build();
try (Response response = client.newCall(request).execute()) {
if (response == null) {
throw new OkHttpException("return response is null");
}
ResponseBody body = response.body();
// 如果使用 string(),当数据大于 1MB 时,容易造成内存溢出。推荐使用 byteStream(),记得关闭操作流
// String str = body.string();
String str = body == null ? null : IOUtils.toString(body.byteStream(), charset);
System.out.println(str);
} catch (SocketTimeoutException e) {
throw new OkHttpException("连接超时", e);
} catch (Exception e) {
throw new OkHttpException(e);
}
}
  • 本文作者: forever杨
  • 本文链接: https://blog.yl-online.top/posts/eb373e45.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。如果文章内容对你有用,请记录到你的笔记中。本博客站点随时会停止服务,请不要收藏、转载!