我们做web开发时,需要经常使用httpclient来请求http服务,有时为了安全起见,服务提供方会提供多个http地址,这样如果我们请求某个ip出现异常,可以重试其他的ip地址,来尽量保证系统的稳定,以下是自定义一个HttpMethod重试机制的简要代码。
HostCluster类定义需要连接的协议、ips[]、重试次数、随机获取一个host等:
-
public class HostCluster {
-
protected static final String HTTP_PROTOCOL = \"http\";
-
protected static final String HTTPS_PROTOCOL = \"https\";
-
-
protected String protocol;
-
protected String[] ips; //contain ip and port
-
-
private int idx;
-
private int retry;
-
-
private Random random;
-
-
public HostCluster(String ipAndPort) {
-
this(HTTP_PROTOCOL, ipAndPort);
-
}
-
-
public HostCluster(String protocol, String ipAndPort) {
-
this(protocol, ipAndPort, 0);
-
}
-
-
public HostCluster(String protocol, String ipAndPort, int retry) {
-
if (StringUtils.isEmpty(ipAndPort)) {
-
throw new IllegalArgumentException(\"invalid constructor params.\");
-
}
-
if (retry < 0) {
-
throw new IllegalArgumentException(\"invalid retry.\");
-
}
-
if (!HTTP_PROTOCOL.equals(protocol) && !HTTPS_PROTOCOL.equals(protocol)) {
-
throw new IllegalArgumentException(\"invalid protocol.\");
-
}
-
-
//split the string
-
String[] splitStr = StringUtils.split(ipAndPort, \",\");
-
-
this.protocol = protocol;
-
this.ips = splitStr;
-
this.retry = retry;
-
-
this.idx = this.ips.length;
-
this.random = new Random();
-
}
-
-
public String randomHost() {
-
int index = this.random.nextInt(idx);
-
log.info(\"randomIp=\" + ips[index]);
-
return this.protocol + \"://\" + ips[index];
-
}
-
-
public boolean isHttps() {
-
return HTTPS_PROTOCOL.equals(protocol);
-
}
-
-
public String getProtocol() {
-
return protocol;
-
}
-
-
public int getRetry() {
-
return retry;
-
}
-
}
-
ClusterRetryHttpMethod从HostCluster获取的randomHost,然后new URI()设置相应的base(GetMethod or PostMethod)
-
public abstract class ClusterRetryHttpMethod<T extends HttpMethod> {
-
protected HostCluster cluster;
-
protected String urlSuffix;
-
protected T base;
-
private Integer retry;
-
-
public ClusterRetryHttpMethod(HostCluster cluster, String urlSuffix) {
-
this(cluster, urlSuffix, null);
-
}
-
-
public ClusterRetryHttpMethod(HostCluster cluster, String urlSuffix, Integer retry) {
-
if (cluster == null || StringUtils.isBlank(urlSuffix)) {
-
throw new IllegalArgumentException(\"invalid params.\");
-
}
-
if (retry != null) {
-
if (retry < 0) {
-
throw new IllegalArgumentException(\"invalid retry.\");
-
} else {
-
this.retry = retry;
-
}
-
}
-
this.cluster = cluster;
-
this.urlSuffix = urlSuffix;
-
-
this.base = initBase();
-
}
-
-
public boolean isHttps() {
-
return this.cluster.isHttps();
-
}
-
-
public void setQueryString(String queryString) {
-
this.base.setQueryString(queryString);
-
}
-
-
public void setQueryString(NameValuePair[] params) {
-
this.base.setQueryString(params);
-
}
-
-
public int getRetry() {
-
return retry == null ? this.cluster.getRetry() : retry;
-
}
-
-
protected abstract T initBase();//子类各自实现,GetMethod or PostMethod
-
-
public T randomMethod() throws Exception {
-
String url = this.randomUrl();
-
if (StringUtils.isBlank(url)) {
-
url = \"/\";
-
}
-
-
this.base.setURI(new URI(url, true));
-
return base;
-
}
-
-
protected String randomUrl() {
-
return cluster.randomHost() + urlSuffix;
-
}
-
}
最后就是怎么调用了,这里使用的是HttpClientPool来调用http连接,关于HttpClientPool详见我的另一篇文章:http://blog.itpub.net/28912557/viewspace-1223241/
-
public class HttpClientPool extends GenericObjectPool<HttpClient> {
-
-
private int httpsPort;
-
-
public HttpClientPool(PoolableObjectFactory<HttpClient> factory) {
-
super(factory);
-
}
-
-
public <T> T doPost(ClusterRetryHttpMethod method, HttpClientDataCallback<T> callback) {
-
HttpClient toUse = null;
-
HttpMethod m = null;
-
int index = 0;
-
if (method == null) {
-
return null;
-
}
-
if (method.isHttps()) {
-
Protocol myhttps = new Protocol(\"https\", new SSLProtocolSocketFactoryImpl(), httpsPort);
-
Protocol.registerProtocol(\"https\", myhttps);
-
}
-
try {
-
toUse = borrowObject();
-
while (index <= method.getRetry()) {
-
try {
-
m = method.randomMethod();
-
toUse.executeMethod(m);
-
T rel = callback.handleResponse(m.getResponseBodyAsString());
-
return rel;
-
} catch (Exception e) {
-
logger.error(\"failed to execute http request.\", e);
-
index++;
-
} finally {
-
try {
-
m.releaseConnection();
-
} catch (Exception e) {
-
// in case fail, ignore and return object
-
}
-
}
-
}
-
} catch (Exception e) {
-
return null;
-
} finally {
-
if (toUse != null) {
-
try {
-
returnObject(toUse);
-
} catch (Exception e) {
-
}
-
}
-
if (method.isHttps()) {
-
try {
-
Protocol.unregisterProtocol(\"https\");
-
} catch (Exception e) {
-
}
-
}
-
}
-
// all retry failed
-
return null;
-
-
}
-
-
-
public int getHttpsPort() {
-
return httpsPort;
-
}
-
-
public void setHttpsPort(int httpsPort) {
-
this.httpsPort = httpsPort;
-
}
-
}
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/28912557/viewspace-1356116/
,如需转载,请注明出处,否则将追究法律责任。