HTTP 在什麼情況下會請求超時?

在做一個程序的時候,設置了請求時間為5秒。

但是經過測試,
1. 如果通過程序請求另一個程序,另一個程序有斷點, 這時候經過多長時間都不會算超時。
2. 請求一個不存在的地址,但其域名是存在的, 超時時間不起作用。
3. 請求一個域名和真實內容都不存在的地址, 超時時間也不起作用,同樣是幾毫秒。

請問,在什麼情況下,才能算做HTTP請求超時呢,是否有幾個實際的例子來說明。


就Http來說,超時分為請求超時和響應超時。而題主的情況,有一個描述是不屬於超時的,先來說下超時的兩種情況。

請求超時,比如現在網路超級不好,當客戶端發起一個請求,通信層開始請求與伺服器建立連接(包括在重試),如果在5S之內還沒有連接到伺服器,那麼認為超時。

響應超時,當我們連接到伺服器時,一般比如url參數(url?key=value)會直接提交到伺服器,比如body類型的參數(Form、JsonBody、key=valuekey1=value1等)我們會通過連接中的stream再手動寫出去,當伺服器接受到請求數據後開始【處理數據-&>響應】,這個【處理數據-&>響應】階段就可能會發生響應超時,比如伺服器去執行資料庫操作,在5S內還沒有對stream做出反饋,那麼客戶端就認為超時(少部分人對下載有誤解,下載則不一樣,因為一直有輸出數據,也就是對stream做了反饋),主動斷開和伺服器的連接。

以上兩種情況,底層一般都是拋出一個TimeoutException的異常,回到題主的問題,舉例說明:

1. 一個不存在的url,但是這個url的域名是存在的,比如:

https://www.google.com?name=limingpwd=123456

這個URL顯然是不存在的,但是域名是存在且可以請求同,這個時候的超時情況是符合上面的兩種描述的,但是如果正確請求,那麼將會響應404。

2. 一個不存在的域名,也就是題主的情況。比如域名沒有被註冊過,或者說註冊了沒有被解析到某個ip上。這種情況一般都會毫秒級別的反饋,得到的異常可能是NotFoundHostException,而不是TimeoutException,所以題主設置的超時時間在這裡是無效的,因為還沒到建立連接判斷超時的那一步。

另外補一個點:一般會setConnectionTimeout、setReadTimeout,看題主只設置了一個超時,不知道是哪個。

現在比如okhttp還提供了setWriteTimeout,比如連接後要寫一個文件出去,而這文件被臨時加鎖,假設客戶端的stream在等待釋放鎖,此時就適用writeTimeout這種情況,這個例子可能比較牽強,但是希望能幫助理解。

------------------------------------------------------2017.06.09-----------------------------------------------------

補充:這段時間有人問我一些問題我覺得再補充一點。

問題1:我設置了Connection超時為10S,Read超時為10S,但是我請求了12、13S就超時了?

回答:這兩個超時不能相加,連接超時10S,假如1S就連接成功了,那麼就不存在連接超時了,然後等待伺服器10S沒響應然後超時,這個時候就是11S。

問題2:我設置了Connection超時為10S,Read超時為10S,但是有時候一兩秒就失敗了,有時候10S左右就失敗了?

回答:一兩秒失敗的情況不屬於超時,它是屬於我上面說過的NotFoundHostException,根本還沒到連接的時候。10S失敗是在連接了10S還沒連接到伺服器,還沒到Read的時候那麼肯定是10S就失敗啦。

問題3:我設置了Connection超時為10S,Read超時為10S,我下載文件的時候,下載了一兩個小時都沒超時呢?

回答:這裡就是對ReadTimeout的不理解了,第一種情況:請求伺服器的一個介面,這個介面直接return了一段文字,毫秒級別的響應不存在超時,那麼如果伺服器去查詢資料庫,假設查詢了1分鐘,這個查詢和客戶端沒任何交互,還在保持著連接,那肯定超時了。第二種情況:請求伺服器的文件,連接成功後伺服器開始發送文件流到客戶端,由於文件比較大,一直發送了一兩個小時還沒發送完,但是這個過程中是一直有和客戶端交互的,也就是發送流到客戶端,但是如果在發送的過程中,有10S的時間中斷髮送了或者沒有發送(但是還保持連接),那麼還是可能發生超時。

------------------------------------------------------2017.06.13-----------------------------------------------------

剛剛有個小夥伴問的,速速補上:

問題4:我設置了Connection超時為10S,Read超時為10S,我上傳文件的時候,上傳了一兩個小時,伺服器也沒做什麼動作,咋也沒超時呢?

回答:這個就是問題3的反問題(物質和反物質原理),用問題3來反過來解釋,客戶端下載的時候只是伺服器輸出,其實客戶端在做接受的流動作,不停的把byte[]寫入文件。同樣的,上傳時伺服器也是不停的在接受文件,所以也不會超時,這個時候出現的超時其實更像是上面提到的WriteTimeout,如果客戶端連接了伺服器,並且OutputStream os = connection.getOutputStream(),但是沒做任何操作,在保持伺服器鏈接(保持outputStream),這就適用WriteTimeout了。


HTTP TIMEOUT不是說你發起了一個請求後,超過一段時間沒人理你喔。

HTTP TIMEOUT分多種情況,但他們都是一個返回,而不是沒人理你。
比如返回408,表示你的請求伺服器收到了,但是那個處理程序(比如網站程序)好像喝大了睡死了,它沒有及時對你的請求做出答覆,因此伺服器返回了一個408。
504表示你通過了一個網關代理,而這個網關沒收到它的上層網關或者目的地伺服器的及時回應(通常也見於堡壘機、防火牆或者CDN)。
還有一些非官方的錯誤代碼,比如IIS下的440表示是你的session過期了(Login Timeout)必須重新登陸一次。


其實HTTP請求的超時分為兩種:

1. 應用層超時,很多HTTP framework本身有超時機制,就是在應用層代碼里啟動一個Timer,如果timer超時則手動取消請求。
2. 傳輸層(比如TCP)超時,TCP本身有重發和超時機制,只不過應用層程序員感知不到。TCP發包的每一個環節都有可能會超時,比如剛開始發sync包,系統會在短時間內做多次重試,一個connect請求,如果不從應用層手動取消,等待60s都是有可能的,當然這個具體的超時值是因系統而異的。

你所說的場景有些是應用層超時,有些是傳輸層超時,所以你會感覺5S(應用層超時值)有時起作用,有時沒作用。


推薦閱讀:

怎樣把 ssh、http 和 https 放到同一埠?
如何看待谷歌 Google 打算用 QUIC 協議替代 TCP/UDP?
http是應用層,ip是網路層,那麼http請求頭部的client ip是怎麼獲取到的呢?
基於傳輸層TCP、UDP協議的自定義應用層協議如何實現?
前端工程師應該對 HTTP 了解到什麼程度?從哪些途徑去熟悉更好?

TAG:HTTPS | HTTP | TCPIP | TCP |