HttpMethod自定义失败重连

我们做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;
    }
}

你可能感兴趣的:(HttpMethod自定义失败重连)