差異處
這裏顯示兩個版本的差異處。
下次修改 | 前次修改 | ||
java:basic:httpurlconnection:readblockingissue [2018/03/21 21:09] tony 建立 |
java:basic:httpurlconnection:readblockingissue [2023/06/25 09:48] (目前版本) |
||
---|---|---|---|
行 2: | 行 2: | ||
====== Read Blocking of the HttpsURLConnection ====== | ====== Read Blocking of the HttpsURLConnection ====== | ||
===== Problem ===== | ===== Problem ===== | ||
+ | 這故事發生在某天service狀態顯示為啟動中,但卻沒執行該執行的工作。後來將heap dump出來,從thread list中看到以下狀況:\\ | ||
+ | {{:java:basic:httpurlconnection:read_blocking_of_httpsurlconnection.png|}}\\ | ||
+ | 我們的URLConnection是有設定timeout的: | ||
+ | <code java> | ||
+ | URLConnection conn = url.openConnection(); | ||
+ | conn.setConnectTimeout(connectionTimeout); | ||
+ | conn.setReadTimeout(readTimeout); | ||
+ | </code> | ||
+ | 為什麼service已經執行好幾天了,還會存在理應timeout的連線呢? | ||
===== How to resolve? ===== | ===== How to resolve? ===== | ||
+ | 從call stack中去查看java原始碼可以發現,在sun.net.www.protocol.https.HttpsClient.afterConnect中,會使用SSLSocketFactory去建立socket並且做handshake,期間並沒有設定readTimeout;如果http server並沒吐訊息或自動中斷連線,就有可能造成client程式block住。在這種情況下,即使你做中斷也沒用。\\ | ||
+ | 目前我們解決的方式是透過一個wrapper SSLSocketFactory,去設定default timeout: | ||
+ | <code java> | ||
+ | private Socket setDefaultProp(Socket socket) throws SocketException{ | ||
+ | socket.setSoTimeout(readTimeout); | ||
+ | return socket; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public Socket createSocket(Socket aS, String aHost, int aPort, boolean aAutoClose) throws IOException { | ||
+ | return setDefaultProp(mSocketFactory.createSocket(aS, aHost, aPort, aAutoClose)); | ||
+ | } | ||
+ | </code> | ||
+ | 而HttpsURLConnection會設定我們自己的SSLSocketFactory: | ||
+ | <code java> | ||
+ | HttpsURLConnection sslconn = (HttpsURLConnection) conn; | ||
+ | sslconn.setSSLSocketFactory(mySSLSocketFactory); | ||
+ | </code> | ||
===== ===== | ===== ===== | ||
---- | ---- | ||
\\ | \\ | ||
~~DISQUS~~ | ~~DISQUS~~ |