2014-05-06 32 views
13

我在調用webservice時使用以下命令來檢查超時,但我想特別檢查是否存在返回的超時錯誤。如何做到這一點:S專門檢查超時錯誤

我有這樣的:

// Timeout 
type Timeout struct { 
    Connect time.Duration 
    ReadWrite time.Duration 
} 

// TimeoutDialer 
func TimeoutDialer(timeout *Timeout) func(net, addr string) (c net.Conn, err error) { 
    return func(netw, addr string) (net.Conn, error) {  
     conn, err := net.DialTimeout(netw, addr, timeout.Connect) 
     if err != nil { 
      return nil, err 
     } 
     conn.SetDeadline(time.Now().Add(timeout.ReadWrite)) 
     return conn, nil 
    } 
} 

// HttpClient 
func HttpClient(config Config) *http.Client { 
    to := &Timeout{ 
     Connect: time.Duration(config.MaxWait) * time.Second, 
     ReadWrite: time.Duration(config.MaxWait) * time.Second, 
    } 

    return &http.Client{ 
     Transport: &http.Transport{ 
      Dial: TimeoutDialer(to), 
     }, 
    } 
} 
+0

忘了提,如果您要爲連接設置絕對截止日期,則應關閉傳輸中的Keepalive。否則,重新使用連接時可能會導致超時。 – JimB

回答

35

從go1.6開始,所有超時錯誤都應該符合net.ErrorTimeout()正確設置。所有你需要檢查的是:

if err, ok := err.(net.Error); ok && err.Timeout() { 

在舊版本中,檢查通過HTTP包超時就比較困難了。

  • 如果您在底層連接上設置了截止日期,您可以使用Timeout()獲得*net.OpError
  • 您可以獲得一個tlsHandshakeTimeoutError(顯然不會導出),它實現了net.Error接口。
  • 你可以得到一個url.Error,如果有網址包內的問題(在初始連接時超時)
  • 你可以得到一個錯誤與「使用封閉網絡連接」如果你打一個暫停時以http.Client.Timeout [GO1設置.3 +](其中稱爲Transport.CancelRequest)。從go1.5開始,這將會正確設置Timeout屬性。

你可以檢查一個net.Error有型開關:

switch err := err.(type) { 
case net.Error: 
    if err.Timeout() { 
     fmt.Println("This was a net.Error with a Timeout") 
    } 
case *url.Error: 
    fmt.Println("This is a *url.Error") 
    if err, ok := err.Err.(net.Error); ok && err.Timeout() { 
     fmt.Println("and it was because of a timeout") 
    } 
} 

一起去< 1.5則需要檢查錯誤字符串的http.Client超時:

if err != nil && strings.Contains(err.Error(), "use of closed network connection") { 
    fmt.Println("Could be from a Transport.CancelRequest") 
} 
+0

完美的作品,謝謝! –

+0

對不起,我應該斷言一個'net.Error',因爲你可以得到超時而不是OpError。 – JimB

+1

因此,使用http.Client.Timeout [go1.3 +],無法檢查Transport.CancelRequest是否超時錯誤?有沒有這方面的錯誤報告?對我來說,這個消息是完全混淆的。 –

10

您希望net.Error接口。 http://golang.org/pkg/net/#Error

if e,ok := err.(net.Error); ok && e.Timeout() { 
    // This was a timeout 
} else if err != nil { 
    // This was an error, but not a timeout 
} 

注意該類型的斷言err.(net.Error)將正確處理nil情況下,如果nil返回的錯誤,短路Timeout檢查爲ok值返回false。

+1

不幸的是,嘗試'response,err:= client.Do(req) if e,ok:= err。(net.Error); OK && e.Timeout(){ \t //這是一個超時 \t fmt.Println( 「超時」) 回報 }'給我什麼:S –

+0

你確定這是一個超時錯誤,然後呢?你可能想添加一個'else if err!= nil'檢查來覆蓋非超時錯誤。 – LinearZoetrope

+0

我將超時(maxwait)設置爲2秒,並且在一個php腳本的睡眠時間爲10秒(因此這應該是一個超時)後面,返回的錯誤是:Get http://api.vagrant/test。 php:read tcp 192.168.33.10:80:I/O timeout –