0
回答
HttpClient重试机制无效
利用AWS快速构建适用于生产的无服务器应用程序,免费试用12个月>>>   
package com.daojia.searchcloud.http.common.kits;

import com.sun.deploy.util.SessionState;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.ServiceUnavailableRetryStrategy;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Created by xingtianyu(code4j) on 2017-7-12.
 */
public class HttpKits {
    private static Logger logger = LogManager.getLogger(HttpKits.class.getName());

    private static final String CHARSET_UTF8 = "UTF-8";

    private static RequestConfig requestConfig ;

    static{
        requestConfig = RequestConfig.custom()
                .setConnectTimeout(10000).setConnectionRequestTimeout(8000)
                .setSocketTimeout(8000).build();
    }

   
    public static String postJson(String url, String json) {
        return postJson(url, null, null, json);
    }

    public static String postJson(String url, String authorName, String authorPass, String json) {
        HttpClient httpClient = null;
        HttpPost httpPost = null;
        String result = null;
        try {
            httpClient = buildHttpClient();
            httpPost = new HttpPost(url);
            httpPost.setConfig(requestConfig);
            StringEntity se = new StringEntity(json, ContentType.APPLICATION_JSON);
            se.setContentType("application/json");
            if (!StringUtils.isBlank(authorName) && !StringUtils.isBlank(authorPass)) {
                String author = getAuthor(authorName, authorPass);
                if (StringUtils.isNotBlank(author)) {
                    httpPost.setHeader("Authorization", author);
                }
            }
            httpPost.setEntity(se);
            HttpResponse response = httpClient.execute(httpPost);
            if (response != null) {
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    result = EntityUtils.toString(resEntity, CHARSET_UTF8);
                }
            }
        } catch (Exception e) {
            logger.error("postEntity error:", e);
        }
        return result;
    }

    private static String getAuthor(String authorName, String authorPass) {

        if (StringUtils.isBlank(authorName) || StringUtils.isBlank(authorPass)) {
            return "";
        }

        //使用base64进行加密
        byte[] tokenByte = org.apache.commons.codec.binary.Base64.encodeBase64((authorName + ":" + authorPass).getBytes());
        //将加密的信息转换为string
        //Basic YFUDIBGDJHFK78HFJDHF==    token的格式
        //把认证信息发到header中
//        post.setHeader("Authorization", "Basic "+token);
        return "Basic " + new String(tokenByte);
    }

    private static CloseableHttpClient buildHttpClient(){
        return HttpClients.custom().setRetryHandler(new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException exception, int executionCount,
                                        HttpContext context) {
                System.out.println("retrying.... "+executionCount);
                if (executionCount > 3) {
                    System.out.println("final try.... "+executionCount);
                    logger.info("retry reach to 3 times");
                    return false;
                }
                if (exception instanceof NoHttpResponseException) {
                    logger.info("NoHttpResponse start to retry times:"+executionCount);
                    System.out.println("NoHttpResponse start to retry times:"+executionCount);
                    return true;
                }
                if (exception instanceof SocketTimeoutException){
                    logger.info("SocketTimeout start to retry times:"+executionCount);
                    System.out.println("SocketTimeout start to retry times:"+executionCount);
                    return true;
                }
                if (exception instanceof ConnectionPoolTimeoutException){
                    logger.info("ConnectionPoolTimeout start to retry times:"+executionCount);
                    System.out.println("ConnectionPoolTimeoutException start to retry times:"+executionCount);
                    return true;
                }
                return false;
            }
        }).build();
    }

}

先贴代码。线上偶尔会有请求失败的异常,异常信息为:org.apache.http.NoHttpResponseException:www.xxxx.com:80 fail to response.

网上查了一下有说这个异常,处理方式 可以通过重试请求来处理,于是添加了上面的代码中的这个方法 :

   private static CloseableHttpClient buildHttpClient(){
        return HttpClients.custom().setRetryHandler(new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException exception, int executionCount,
                                        HttpContext context) {
                System.out.println("retrying.... "+executionCount);
                if (executionCount > 3) {
                    System.out.println("final try.... "+executionCount);
                    logger.info("retry reach to 3 times");
                    return false;
                }
                if (exception instanceof NoHttpResponseException) {
                    logger.info("NoHttpResponse start to retry times:"+executionCount);
                    System.out.println("NoHttpResponse start to retry times:"+executionCount);
                    return true;
                }
                if (exception instanceof SocketTimeoutException){
                    logger.info("SocketTimeout start to retry times:"+executionCount);
                    System.out.println("SocketTimeout start to retry times:"+executionCount);
                    return true;
                }
                if (exception instanceof ConnectionPoolTimeoutException){
                    logger.info("ConnectionPoolTimeout start to retry times:"+executionCount);
                    System.out.println("ConnectionPoolTimeoutException start to retry times:"+executionCount);
                    return true;
                }
                return false;
            }
        }).build();
    }

}

 

还有这个socket超时时间也是这次添加的。

private static RequestConfig requestConfig ;

    static{
        requestConfig = RequestConfig.custom()
                .setConnectTimeout(10000).setConnectionRequestTimeout(8000)
                .setSocketTimeout(8000).build();
    }

但是放到测试环境,仍旧会有超时的请求,异常变成:java.net,SocketTimeoutException  Read timed out.

很纳闷儿,老问题没解决新问题出现了。。。 有没有遇到相同情况的呢?

ps: QPS平均75,8台机器调用,服务部署在三台机器上。

 

<无标签>
举报
coder4j
发帖于1周前 0回/24阅
顶部