美文网首页
HttpClient重试机制 --自定义HttpRequestR

HttpClient重试机制 --自定义HttpRequestR

作者: 尼小摩 | 来源:发表于2018-12-13 21:25 被阅读60次

通过http做接口调用请求的时候,常常会因为网络抖动或者其他未知原因,造成接口在某个瞬间访问不了。此时需要增加重试机制。

HttpClient有重试机制,通过设置httpclient 的retryHandler来实现。

封装了一个HttpClientUtils的工具类中的获取线程池并设置retry机制的方法,代码如下:

package com.ly.storm.config;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.net.ssl.SSLException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

/**
 * @Auther: fc.w
 * @Date: 2018/12/12
 */
public class HttpClientUtils {

    private static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);

    private static final RequestConfig REQUEST_CONFIG_TIME_OUT = RequestConfig.custom()
            .setSocketTimeout(20000)
            .setConnectTimeout(50000)
            .setConnectionRequestTimeout(50000)
            .build();

    private static PoolingHttpClientConnectionManager cm = null;

    @PostConstruct
    public void init() {
        cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(1000);
        cm.setDefaultMaxPerRoute(1000);
    }

    /**
     *
     * @param isPooled 是否使用连接池
     * @return
     */
    public static CloseableHttpClient getClient(boolean isPooled) {
        HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException e, int retryTimes, HttpContext httpContext) {
                if (retryTimes > 2) {
                    return false;
                }
                if (e instanceof UnknownHostException || e instanceof ConnectTimeoutException
                        || !(e instanceof SSLException) || e instanceof NoHttpResponseException) {
                    return true;
                }

                HttpClientContext clientContext = HttpClientContext.adapt(httpContext);
                HttpRequest request = clientContext.getRequest();
                boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
                if (idempotent) {
                    // 如果请求被认为是幂等的,那么就重试。即重复执行不影响程序其他效果的
                    return true;
                }
                return false;
            }
        };
        if (isPooled) {
            return HttpClients.custom().setConnectionManager(cm).setRetryHandler(retryHandler).build();
        }
        return HttpClients.createDefault();

    }

    public static final String doPostWithRequest(String path, HttpServletRequest request) {
        Enumeration params = request.getParameterNames();
        List<NameValuePair> nameValuePairs = Lists.newArrayList();
        while (params.hasMoreElements()) {
            String paramName = (String) params.nextElement();
            nameValuePairs.add(new BasicNameValuePair(paramName, request.getParameter(paramName)));
        }
        HttpPost httpPost = new HttpPost(path);

        httpPost.setConfig(REQUEST_CONFIG_TIME_OUT);
        try {
            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
            return execReq(httpPost);
        } catch (UnsupportedEncodingException e) {
            logger.error("do post error: ", e);
        }
        return "";
    }


    public static final String doPost(String path, Map<String, Object> params) {
        logger.debug("doPost from " + path, params);
        HttpPost httpPost = new HttpPost(path);

        httpPost.setConfig(REQUEST_CONFIG_TIME_OUT);
        try {
            httpPost.setEntity(new UrlEncodedFormEntity(createParams(params)));

            String bodyAsString = execReq(httpPost);
            if (bodyAsString != null) return bodyAsString;

        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage(), e);
        }

        return errorResponse("-2", "unknown error");
    }

    private static List<NameValuePair> createParams(Map<String, Object> params) {
        List<NameValuePair> nameValuePairs = Lists.newArrayList();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            nameValuePairs.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
        }
        return nameValuePairs;
    }

    private static String execReq(HttpPost httpPost) {
        try {
            CloseableHttpResponse response = getClient(true).execute(httpPost);
            if (response != null) {
                try {
                    if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                        return EntityUtils.toString(response.getEntity());
                    } else {
                        return errorResponse(String.valueOf(response.getStatusLine().getStatusCode()),
                                "http post request error: " + httpPost.getURI());
                    }
                } finally {
                    EntityUtils.consume(response.getEntity());
                }
            } else {
                return errorResponse("-1", "response is null");
            }

        } catch (IOException e) {
            logger.error("doPost error: ", e);
        }
        return errorResponse("-3", "unknown error");
    }

    private static String errorResponse(String code, String msg) {
        return JSON.toJSONString(ImmutableMap.of("code", code, "msg", msg));
    }
}

相关文章

网友评论

      本文标题:HttpClient重试机制 --自定义HttpRequestR

      本文链接:https://www.haomeiwen.com/subject/tvkihqtx.html