我们做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 {
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 {
private int httpsPort;
public HttpClientPool(PoolableObjectFactory factory) {
super(factory);
}
public T doPost(ClusterRetryHttpMethod method, HttpClientDataCallback 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;
}
}
网友评论