# 问题

http 请求发起后接收不到返回数据!!!【测试环境没出问题,发到正式环境就有问题】

项目中通过 restTemplate 发起请求:

1
2
3
4
5
6
7
8
log.info("请求入参:{}",JSON.toJSONString(request));//打印日志1
// 配置http请求的连接超时时间和读取超时时间
HttpsClientRequestFactory factory = new HttpsClientRequestFactory();
factory.setConnectTimeout(60 * 1000);
factory.setReadTimeout(5 * 60 * 1000);
RestTemplate restTemplate = new RestTemplate(factory);
Result<InventoryResult> result = restTemplate.postForObject(address.concat(inventoryUrl), request, Result.class);
log.info("库存同步,返回数据: {}", result);//打印日志2

  • 打印日志 1 内容为:

http 请求入参:{data=[{ productStatus=10,skuCode=null}], messageId=ewpfpr1t6ey5r6qj0su0w1h6rt73hr,token=vgvU5EJKuZbuHii7WH6pTINp40ZRicaqLz4dq5P7L6pDzWir8EEGZhCKPucQjljsw69EHasEy+iJfdTofDg==}

  • 打印日志 2 内容为:没有打印内容!!!

  • 最后发现是因为测试环境中数据量较小,http 请求后,很快能得到相应,而正式环境数据量较大,没有及时得到响应,连接或者读取超时!!!

# 解决方式

# 第一种
  1. 添加 HttpsClientRequestFactory 类,并继承 SimpleClientHttpRequestFactory

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    /**
    * 兼容调Https接口
    */
    public class HttpsClientRequestFactory extends SimpleClientHttpRequestFactory {

    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod)
    throws IOException {
    if (connection instanceof HttpsURLConnection) {
    prepareHttpsConnection((HttpsURLConnection) connection);
    }
    super.prepareConnection(connection, httpMethod);
    }

    private void prepareHttpsConnection(HttpsURLConnection connection) {
    connection.setHostnameVerifier(new SkipHostnameVerifier());
    try {
    connection.setSSLSocketFactory(createSslSocketFactory());
    }
    catch (Exception ex) {
    // Ignore
    }
    }

    private SSLSocketFactory createSslSocketFactory() throws Exception {
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, new TrustManager[] { new SkipX509TrustManager() },
    new SecureRandom());
    return context.getSocketFactory();
    }

    private class SkipHostnameVerifier implements HostnameVerifier {

    @Override
    public boolean verify(String s, SSLSession sslSession) {
    return true;
    }

    }

    private static class SkipX509TrustManager implements X509TrustManager {

    @Override
    public X509Certificate[] getAcceptedIssuers() {
    return new X509Certificate[0];
    }

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType) {
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType) {
    }

    }
    }

  2. 使用 restTemplate 发起请求前先设置连接和超时时间或者通过容器加载配置类然后设置超时时间

    1
    2
    3
    4
    5
    6
    //配置http请求的连接超时时间和读取超时时间
    HttpsClientRequestFactory factory = new HttpsClientRequestFactory();
    factory.setConnectTimeout(60 * 1000);
    factory.setReadTimeout(5 * 60 * 1000);
    RestTemplate restTemplate = new RestTemplate(factory);
    BaseResult<QueryInventoryResult> result = restTemplate.postForObject(address.concat(inventoryUrl), request, Result.class);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @Configuration
    public class RestConfig {

    //60 * 1000
    @Value("${rest.connectTimeout:60000}")
    private int connectTimeout;

    //5 * 60 * 1000
    @Value("${rest.readTimeout:300000}")
    private int readTimeout;

    @Bean
    public RestTemplate restTemplate() {
    SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
    simpleClientHttpRequestFactory.setConnectTimeout(connectTimeout);
    simpleClientHttpRequestFactory.setReadTimeout(readTimeout);
    RestTemplate restTemplate = new RestTemplate(simpleClientHttpRequestFactory);
    return restTemplate;
    }

# 第二种

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Configuration
public class RestConfig {

//60 * 1000
@Value("${rest.connectTimeout:60000}")
private int connectTimeout;

//5 * 60 * 1000
@Value("${rest.readTimeout:300000}")
private int readTimeout;

@Value("${rest.connectionRequestTimeout:300000}")
private int connectionRequestTimeout;

/**
* 使用 HttpComponentsClientHttpRequestFactory创建http请求(推荐)
*/
@Bean
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setConnectionRequestTimeout(connectionRequestTimeout);
httpRequestFactory.setConnectTimeout(connectTimeout);
httpRequestFactory.setReadTimeout(readTimeout);
return new RestTemplate(httpRequestFactory);

}
}

# 第三种(基于第二种升级)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Configuration
public class RestConfig {


/**
* 高并发采用HttpClient连接池
*/
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(httpRequestFactory());
}


@Bean
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}


@Bean
public HttpClient httpClient() {
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
//设置整个连接池最大连接数
connectionManager.setMaxTotal(1000);
//路由是对maxTotal的细分
connectionManager.setDefaultMaxPerRoute(100);
//定义不活动的时间(毫秒),超过的连接从连接池拿取需要重新验证
connectionManager.setValidateAfterInactivity(200);
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(30000) //返回数据的超时时间
.setConnectTimeout(20000) //连接上服务器的超时时间
.setConnectionRequestTimeout(1000) //从连接池中获取连接的超时时间
.build();
return HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
.evictIdleConnections(2, TimeUnit.SECONDS) //保持空闲的最大时间
.build();
}
}