2016-12-21 65 views
0

我對golang編碼相當陌生,並且正在爲恐慌/恢復過程尋求錯誤的url請求而掙扎。以下是查詢URL列表並輸出響應的腳本。有時會輸入錯誤的URL或服務器關閉,並且HTTP請求失敗會導致恐慌。我不清楚如何從中恢復並繼續。我想讓程序從恐慌中恢復,記錄錯誤的URL和錯誤,然後繼續輸出失敗的url和錯誤信息,並返回其他正常url響應數據的url列表。golang http請求錯誤恐慌恢復

package main 

import (
    "fmt" 
    "net/http" 
) 

var urls = []string{ 
    "http://www.google.com",  //good url, 200 
    "http://www.googlegoogle.com/", //bad url 
    "http://www.zoogle.com",  //500 example 
} 

//CONCURRENT HTTP REQUESTS ------------------------------------------- 
func MakeRequest(url string, ch chan<- string) { 
    resp, err := http.Get(url) 
    if err != nil { 
     fmt.Println("Error Triggered", err) 
     ch <- fmt.Sprintf("err: %s", err) 
    } 
    ch <- fmt.Sprintf("url: %s, status: %s ", url, resp.Status) // put response into a channel 
    resp.Body.Close() 
} 

func main() { 
    output := make([][]string, 0) //define an array to hold responses 

    //PANIC RECOVER------------------------------ 
    defer func() { //catch or finally 
     if r := recover(); r != nil { //catch 
      fmt.Println("Recover Triggered: ", r) 
     } 
    }() 

    //MAKE URL REQUESTS---------------------------------------------- 
    for _, url := range urls { 
     ch := make(chan string)     //create a channel for each request 
     go MakeRequest(url, ch)     //make concurrent http request 
     output = append(output, []string{<-ch}) //append output to an array 
    } 

    //PRINT OUTPUT ---------------------- 
    for _, value := range output { 
     fmt.Println(value) 
    } 
} 

我正在尋找類似的輸出:

[URL:http://www.google.com,狀態:200 OK]

[URL:http://www.googlegoogle.com,ERR:沒有這樣的主持人]

[ url:http://www.zoogle.com,狀態:500內部服務器錯誤]

+2

除非您由於某種原因特別恐慌,否則恐慌表示程序中有錯誤。修復錯誤,使您不會有任何恐慌情緒從中恢復。 – JimB

+0

這個邏輯有幫助,看起來像一個錯誤的情況下,我沒有什麼可以爲resp.Status放入「ch」。 如果我改變處理恐慌停止的錯誤,我可以弄清楚如何解決。 –

+0

如果err不爲零,那麼不僅可以resp回零,但要注意,如果err不是零,那麼resp可能不是零,但是如果嘗試解引用它,會導致恐慌!它並不是專門爲這個函數調用的方式,但文件walker接口確實有這種行爲(至少在go的舊版本中),當err不爲零時,返回的另一個值不是零,但它是一個垃圾值無法解除引用。 – Rob

回答

1

謝謝吉姆B.我認爲恐慌是由請求觸發的,但它是th e嘗試使用「resp.Status」來請求失敗,因爲它不存在。如果沒有錯誤,我將錯誤處理修改爲只在「ch」中放置resp.Status。在發生錯誤的情況下,我用錯誤值將不同的響應替換爲「ch」。沒有必要恢復,因爲沒有恐慌觸發。

func MakeRequest(url string, ch chan<- string) { 
    resp, err := http.Get(url) 
    if err != nil { 
     ch <- fmt.Sprintf("url: %s, err: %s ", url, err) 
    } else { 
     ch <- fmt.Sprintf("url: %s, status: %s ", url, resp.Status) // put response into a channel 
     defer resp.Body.Close() 
    } 
} 

輸出現在是:

[URL:http://www.google.com,狀態:200 OK]

[URL:http://www.googlegoogle.com/,ERR:獲取http://www.googlegoogle.com/:撥打TCP:查找www.googlegoogle.com:無這樣的主持人]

[URL:http://www.zoogle.com,狀態:500內部服務器錯誤]

0

唯一的地方,我願意(做)地方恢復:在「障礙」。

「故障屏障」是集中捕捉問題的最高位置。它通常是新的goroutine產生的地方(即:按照http接受)。在ServeHTTP方法中,您可能希望捕獲並記錄個別恐慌情況,而無需重新啓動服務器(通常這種恐慌通常是無用的ptr derefs)。您可能會在無法檢查需要知道的情況的地方看到恢復 - 例如文件句柄是否已關閉。 (只需關閉並處理可能的恐慌)。

我有一個大的代碼庫,只使用恢復2或3次。它們僅適用於上述情況,我只是爲了確保問題具體記錄在案。我會做一個恢復只是爲了記錄消息,即使我仍然要os.Exit並讓腳本啓動我重新啓動我。