Java之HttpURLConnection的變態事: Keep-Alive


HttpURLConnection的變態事: Keep-Alive

JDK自帶的HttpURLConnection默認啟動Keep-Alive, 使用后的HttpURLConnection會放入池里重用. 相關描述:

What does the current JDK do for Keep-Alive?

The JDK supports both HTTP/1.1 and HTTP/1.0 persistent connections.

When the application finishes reading the response body or when the application calls close() on the InputStream returned by URLConnection.getInputStream(), the JDK's HTTP protocol handler will try to clean up the connection and if successful, put the connection into a connection cache for reuse by future HTTP requests.

The support for HTTP keep-Alive is done transparently. However, it can be controlled by system properties http.keepAlive, and http.maxConnections, as well as by HTTP/1.1 specified request and response headers.

The system properties that control the behavior of Keep-Alive are:

http.keepAlive=<boolean>
default: true

Indicates if keep alive (persistent) connections should be supported.

http.maxConnections=<int>
default: 5

Indicates the maximum number of connections per destination to be kept alive at any given time

HTTP header that influences connection persistence is:

Connection: close

If the "Connection" header is specified with the value "close" in either the request or the response header fields, it indicates that the connection should not be considered 'persistent' after the current request/response is complete.

The current implementation doesn't buffer the response body. Which means that the application has to finish reading the response body or call close() to abandon the rest of the response body, in order for that connection to be reused. Furthermore, current implementation will not try block-reading when cleaning up the connection, meaning if the whole response body is not available, the connection will not be reused.

如果服務端不支持Keep-Alive, 這種默認行為就會帶來很多蛋疼的事, 舉個例子:

mogilefs服務端默認沒有啟用Keep-Alive. 使用HttpURLConnection上傳多個文件時, 由於Keep-Alive這種重用特性,導致for循環中第一個文件后的其實PUT請求卡死! 直到Socket Request Timeout! 這種行為實在很變態!

解決辦法在上面描述已經提及, 經測試, 完成可行:
(1)System.setProperty("http.keepAlive", String.valueOf(false));
(2)conn.setRequestProperty("Connection", "close");
根據個人興趣選擇其一即可.

以下是mogilefs上傳多個文件的實現(其實就是HttpURLConnection的PUT請求):

public static String upload(String uri, int size, InputStream content) throws DfsClientException, MalformedURLException, IOException {

  HttpURLConnection conn = null;
  try {
   conn = (HttpURLConnection) new URL(uri).openConnection();
   System.out.println(conn.hashCode());
   conn.setFixedLengthStreamingMode(size);

   conn.setUseCaches(false);
   conn.setDoInput(true);
   conn.setDoOutput(true);
   conn.setConnectTimeout(1000);
   conn.setReadTimeout(2000);
   conn.setRequestMethod("PUT");
   //System.setProperty("http.keepAlive", String.valueOf(false));
   conn.setRequestProperty("Connection", "close");

   conn.connect();

   System.out.println(conn.usingProxy());
   OutputStream out = conn.getOutputStream();
   for (int bt = 0; (bt = content.read()) != -1;) {
    out.write(bt);
   }
   out.close();

   int code = conn.getResponseCode();
   StringBuilder sb = new StringBuilder();
   InputStream in = conn.getErrorStream();
   if (in == null) {
    in = conn.getInputStream();
   }
   if (in != null) {
    BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    for (String line = null; (line = reader.readLine()) != null;) {
     sb.append(line);
    }
    reader.close();
   }

   System.out.format("RESP[%d] %s", code, sb);
   System.out.println(uri);
  } finally {
   if (conn != null) {
    conn.disconnect();
   }
  }

  return uri.replace("/upload", "/download");
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM