httpclient参数配置
序
这⾥简单解释⼀下httpclient⼀些关键参数的配置
超时时间
final RequestConfig requestConfig = RequestConfig.custom()
.tSocketTimeout(SOCKET_TIMEOUT)
.tConnectTimeout(CONNECTION_TIMEOUT)
.tCookieSpec(CookieSpecs.IGNORE_COOKIES).build();
这⾥设置了socket_timeout以及connection_timeout
KeepAliveStrategy
httpclient默认提供了⼀个策略
httpclient-4.5.3-sources.jar!/org/apache/http/impl/client/DefaultConnectionKeepAliveStrategy.java
@Contract(threading = ThreadingBehavior.IMMUTABLE)
public class DefaultConnectionKeepAliveStrategy implements ConnectionKeepAliveStrategy {
public static final DefaultConnectionKeepAliveStrategy INSTANCE = new DefaultConnectionKeepAliveStrategy();
@Override
public long getKeepAliveDuration(final HttpRespon respon, final HttpContext context) {
final HeaderElementIterator it = new BasicHeaderElementIterator(
respon.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
final HeaderElement he = it.nextElement();
final String param = he.getName();
final String value = he.getValue();
if (value != null && param.equalsIgnoreCa("timeout")) {
try {
return Long.parLong(value) * 1000;
} catch(final NumberFormatException ignore) {
}
}
}
return -1;
}
}
默认的话,是从respon⾥头读timeout参数的,没有读到则设置为-1,这个代表⽆穷,这样设置是有点问题了,如果是https链接的话,则可能会经常报
Caud by: java.SocketTimeoutException: Read timed out
at java.SocketInputStream.socketRead0(Native Method)
at java.SocketInputStream.socketRead(SocketInputStream.java:116)
at ad(SocketInputStream.java:170)
at ad(SocketInputStream.java:141)
at sun.curity.adFully(InputRecord.java:465)
at sun.curity.ad(InputRecord.java:503)
at sun.curity.adRecord(SSLSocketImpl.java:973)
at sun.curity.adDataRecord(SSLSocketImpl.java:930)
at sun.curity.ad(AppInputStream.java:105)
HTTP规范没有确定⼀个持久连接可能或应该保持活动多长时间。⼀些HTTP服务器使⽤⾮标准的头部信息Keep-Alive来告诉客户端它们想在服务器端保持连接活动的周期秒数。如果这个信息可⽤,HttClient就会利⽤这个它。如果头部信息Keep-Alive在响应中不存
在,HttpClient假设连接⽆限期的保持活动。然⽽许多现实中的HTTP服务器配置了在特定不活动周期之后丢掉持久连接来保存系统资源,往往这是不通知客户端的。
这⾥可以在此基础上重写⼀个,这⾥设置为5秒
ConnectionKeepAliveStrategy keepAliveStrategy = new DefaultConnectionKeepAliveStrategy() {
@Override
public long getKeepAliveDuration(final HttpRespon respon, final HttpContext context) {
long keepAlive = KeepAliveDuration(respon, context);
if (keepAlive == -1) {
keepAlive = 5000;
}
return keepAlive;
}
};
Connection eviction policy
⼀个经典的阻塞 I/O 模型的主要缺点是⽹络套接字仅当 I/O 操作阻塞时才可以响应 I/O 事件。当⼀个连接被释放返回管理器时,它可以被保持活动状态⽽却不能监控套接字的状态和响应任何 I/O 事件。如果连接在服务器端关闭,那么客户端连接也不能去侦测连接状态中的变化和关闭本端的套接字去作出适当响应。
HttpClient 通过测试连接是否是过时的来尝试去减轻这个问题,这已经不再有效了,因为它已经在服务器端关闭了,之前使⽤执⾏ HTTP 请求的连接。过时的连接检查也并不是 100%
的稳定,反⽽对每次请求执⾏还要增加10到30毫秒的开销。唯⼀可⾏的⽽不涉及到每个对空闲连接的套接字模型线程解决⽅案,是使⽤专⽤的监控线程来收回因为长时间不活动⽽被认为是过期的连接。监控线程可以周期地调⽤
ClientConnectionManager#cloExpiredConnections()⽅法来关闭所有过期的连接,从连接池中收回关闭的连接。它也可以选择性调⽤ClientConnectionManager#cloIdleConnections()⽅法来关闭所有已经空 闲超过给定时间周期的连接。
官⽅提供了⼀个实例
public static class IdleConnectionMonitorThread extends Thread {
milprivate final HttpClientConnectionManager connMgr;
private volatile boolean shutdown;
public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) {
super();
}
@Override
public void run() {
try {
while (!shutdown) {
synchronized (this) {
wait(5000);
// Clo expired connections
connMgr.cloExpiredConnections();
// Optionally, clo connections
// that have been idle longer than 30 c
connMgr.cloIdleConnections(30, TimeUnit.SECONDS);
}
}
} catch (InterruptedException ex) {
// terminate
}
ogs}
public void shutdown() {
shutdown = true;
synchronized (this) {
notifyAll();
}
}
}
在spring cloud netflix zuul中则提供了类似的定时器,只不过参数是写死的
spring-cloud-netflix-core/1.2.6.RELEASE/spring-cloud-netflix-core-1.2.6.RELEASE-
sources.jar!/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java
private final Timer connectionManagerTimer = new Timer(
"tionManagerTimer", true);
@PostConstruct
private void initialize() {
this.httpClient = newClient();
SOCKET_TIMEOUT.addCallback(this.clientloader);
CONNECTION_TIMEOUT.addCallback(this.clientloader);
@Override
public void run() {
if (tionManager == null) {
return;
}
tionManager.cloExpiredConnections();
}
}, 30000, 5000);
}
每30秒清理⼀次失效的connection,但是这⾥的cloExpiredConnections是依赖connTimeToLive参数以及keep alive strategy 设置的。
httpcore-4.4.6-sources.jar!/org/apache/http/pool/AbstractConnPool.java
/**
* Clos expired connections and evicts them from the pool.
*/
public void cloExpired() {
final long now = System.currentTimeMillis();
enumAvailable(new PoolEntryCallback<T, C>() {
@Override
public void process(final PoolEntry<T, C> entry) {
if (entry.isExpired(now)) {
entry.clo();
}
}
});
}
httpcore-4.4.6-sources.jar!/org/apache/http/pool/PoolEntry.java
public synchronized boolean isExpired(final long now) {
return now >= piry;
}
public PoolEntry(final String id, final T route, final C conn,
amalafinal long timeToLive, final TimeUnit tunit) {
super();
this.id = id;
< = conn;
this.updated = ated;
if (timeToLive > 0) {
this.validityDeadline = ated + Millis(timeToLive);
h p} el {
this.validityDeadline = Long.MAX_VALUE;
}
}
public synchronized void updateExpiry(final long time, final TimeUnit tunit) {
this.updated = System.currentTimeMillis();
final long newExpiry;
if (time > 0) {
newExpiry = this.updated + Millis(time);
} el {
newExpiry = Long.MAX_VALUE;
}
}
如果是-1,则这⾥expiry为⽆穷⼤。那么cloExpiredConnections其实是⽆效的。但是还依赖⼀个keep alive strategy,它会去设置updateExpiry
httpclient-4.5.3-sources.jar!/org/apache/http/impl/execchain/MainClientExec.java
@Override
public CloableHttpRespon execute(
职业资格认证培训final HttpRoute route,
final HttpRequestWrapper request,
final HttpClientContext context,
final HttpExecutionAware execAware) throws IOException, HttpException {
AuthState targetAuthState = TargetAuthState();
if (targetAuthState == null) {
targetAuthState = new AuthState();
context.tAttribute(HttpClientContext.TARGET_AUTH_STATE, targetAuthState);
}
考研多少分过线AuthState proxyAuthState = ProxyAuthState();
if (proxyAuthState == null) {
proxyAuthState = new AuthState();
context.tAttribute(HttpClientContext.PROXY_AUTH_STATE, proxyAuthState);
}
if (request instanceof HttpEntityEnclosingRequest) {
}
Object urToken = UrToken();
final ConnectionRequest connRequest = questConnection(route, urToken);
少儿英语系列if (execAware != null) {
if (execAware.isAborted()) {
connRequest.cancel();
throw new RequestAbortedException("Request aborted");
} el {
execAware.tCancellable(connRequest);
}
}
final RequestConfig config = RequestConfig();
final HttpClientConnection managedConn;
try {
conductivityfinal int timeout = ConnectionRequestTimeout();
managedConn = (timeout > 0 ? timeout : 0, TimeUnit.MILLISECONDS);
} catch(final InterruptedException interrupted) {
aiwThread.currentThread().interrupt();
throw new RequestAbortedException("Request aborted", interrupted);
} catch(final ExecutionException ex) {
Throwable cau = ex.getCau();
if (cau == null) {
cau = ex;
}
throw new RequestAbortedException("Request execution failed", cau);
}
context.tAttribute(HttpCoreContext.HTTP_CONNECTION, managedConn);
if (config.isStaleConnectionCheckEnabled()) {
adj