如何自定义长链接策略

此文已由做者赵慧莉受权网易云社区发布。
java

欢迎访问网易云社区,了解更多网易技术产品运营经验。web

1、前言


最近在作内容分发网络(Content Delivery Network,简称 CDN)CDN的后端线上回归集监控时,经常出现连续执行多个用例时会报“org.apache.http.NoHttpResponseException”错误,而单个执行一个用例就不会报这种错误。通过分析为何接口测试时不会出现这种问题,而线上回归的时候就会触发这种错误呢?缘由是因为线上的回归集是为了验证明际的状况要检查CDN是否部署成功,因此线上一个用例的执行时间是30分钟之上,而线下接口测试只须要毫秒级别。接下来我将介绍下为何会出现“org.apache.http.NoHttpResponseException”,以及如何解决这种问题。apache


2、出现“org.apache.http.NoHttpResponseException”的缘由


HttpClient的实现类为CloseableHttpClient。建立CloseableHttpClient实例有两种方式: (1)使用CloseableHttpClient的工厂类HttpClients的方法来建立实例。HttpClients提供了根据各类默认配置来建立CloseableHttpClient实例的快捷方法。最简单的实例化方式是调用HttpClients.createDefault()。 (2)使用CloseableHttpClient的builder类HttpClientBuilder,先对一些属性进行配置,再调用build方法来建立实例。上面的HttpClients.createDefault()实际上调用的也就是HttpClientBuilder.create().build()。 可是在测试的时候连续执行多个方法的时候就会报错,直接执行其中的一个测试方法就不会有这种问题:后端


java.lang.AssertionError: org.apache.http.NoHttpResponseException: nos-yq-yanlian.netease.com:8080 failed to respond
    at org.testng.Assert.fail(Assert.java:89)
    at com.netease.pubncdn.test.testcase.OnlineDomainDeployTest.testCreateHttpDomain(OnlineDomainDeployTest.java:192)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

通过查询资料发现:Http规范没有规定一个持久链接应该保持存活多久。有些Http服务器使用非标准的Keep-Alive头消息和客户端进行交互,服务器端会保持数秒时间内保持链接。HttpClient也会利用这个头消息。若是服务器返回的响应中没有包含Keep-Alive头消息,HttpClient会认为这个链接能够永远保持。然而,不少服务器都会在不通知客户端的状况下,关闭必定时间内不活动的链接,来节省服务器资源。在某些状况下默认的策略显得太乐观,咱们可能须要自定义链接存活策略。安全


3、自定义长链接策略的方法


经过以下代码能够自定义链接存活策略:服务器


CloseableHttpClient client = HttpClients.custom()  
        .setKeepAliveStrategy(keepAliveStrategy)  
        .build();
ConnectionKeepAliveStrategy keepAliveStrategy = new ConnectionKeepAliveStrategy() {  
    public long getKeepAliveDuration(HttpResponse response, HttpContext context) {  
        // Honor 'keep-alive' header  
        HeaderElementIterator it = new BasicHeaderElementIterator(  
                response.headerIterator(HTTP.CONN_KEEP_ALIVE));  
        while (it.hasNext()) {  
            HeaderElement he = it.nextElement();  
            String param = he.getName();  
            String value = he.getValue();  
            if (value != null && param.equalsIgnoreCase("timeout")) {  
                try {  
                    return Long.parseLong(value) * 1000;  
                } catch(NumberFormatException ignore) {  
                }  
            }  
        }  
        HttpHost target = (HttpHost) context.getAttribute(  
                HttpClientContext.HTTP_TARGET_HOST);  
        if ("www.baidu.com".equalsIgnoreCase(target.getHostName())) {  
            // Keep alive for 5 seconds only  
            return 5 * 1000;  
        } else {  
            // otherwise keep alive for 30 seconds  
            return 30 * 1000;  
        }  
    }  
};

4、CDN中如何解决报错问题


经过(三)中的方式能够解决“org.apache.http.NoHttpResponseException”报错的问题,可是考虑到实际的应用场景不适合此种方法。由于一次请求到下次请求之间的间隔为30分钟以上,不适合将链接时间改成30分钟以上(由于不少服务器都会在不通知客户端的状况下,关闭必定时间内不活动的链接,来节省服务器资源)。 修改测试代码为不在@BeforeClass时进行建立实例,而是在每一个测试用例里面进行建立实例来规避的解决这种问题。网络


5、总结


为了定位上述的报错问题,须要了解使用HttpClient请求一个Http请求的步骤,以及如何自定义链接存活策略。在查到解决办法后要考虑是否真正适合咱们的应用场景,以及采用了这种方式是否会形成资源浪费,最终选择适合的方式来规避的解决这个问题。测试


免费体验云安全(易盾)内容安全、验证码等服务
ui

更多网易技术、产品、运营经验分享请点击spa


相关文章:
【推荐】 Gradle task

相关文章
相关标签/搜索