如何自定義長鏈接策略

此文已由做者趙慧莉受權網易雲社區發佈。
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

相關文章
相關標籤/搜索