【问题标题】:golang http request error panic recovergolang http请求错误恐慌恢复
【发布时间】:2017-05-07 11:22:17
【问题描述】:

我对使用 golang 进行编码还很陌生,并且正在为错误的 url 请求处理恐慌/恢复过程。下面是一个查询 URL 列表并输出响应的脚本。有时会输入错误的 url 或服务器关闭,并且 HTTP 请求失败,这会导致恐慌。我不清楚如何从中恢复并继续。我希望程序从恐慌中恢复,记录错误的 url 和错误,并继续输出失败的 url 和错误的 url 列表以及其余正常 url 响应数据。

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)
    }
}

我正在寻找类似于以下内容的输出:

[网址:http://www.google.com,状态:200 OK]

[url:http://www.googlegoogle.com,错误:没有这样的主机]

[url:http://www.zoogle.com,状态:500 内部服务器错误]

【问题讨论】:

  • 除非您出于某种原因特别恐慌,否则恐慌表明您的程序中有错误。修复错误,这样您就不会出现任何需要恢复的恐慌。
  • 该逻辑有帮助,看起来在出现错误的情况下,我没有什么可以为 resp.Status 输入“ch”。如果我修改错误处理恐慌停止,我可以弄清楚如何解决。
  • resp 不仅可以在 err 不为 nil 时返回 nil,而且要注意,如果 err 不为 nil,则 resp 可能不为 nil,但如果您尝试取消引用,则会导致恐慌它!对于这个函数调用,它并不是专门采用这种方式,但是文件 walker 接口确实有这种行为(至少在旧版本的 go 中),当 err 不是 nil 时,返回的另一个值不是 nil,但它是无法取消引用的垃圾值。
  • 我尝试使用 recover() ,然后从他们那里返回,但没有成功。

标签: http go request recover panic


【解决方案1】:

感谢 Jim B。我认为恐慌是由请求触发的,但它是尝试使用“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()
    }
}

现在的输出是:

[网址:http://www.google.com,状态:200 OK]

[url: http://www.googlegoogle.com/, err: Get http://www.googlegoogle.com/: dial tcp: lookup www.googlegoogle.com: no such host]

[url:http://www.zoogle.com,状态:500 内部服务器错误]

【讨论】:

    【解决方案2】:

    我会(并且会)恢复的唯一地方是:在“故障屏障”中。

    “故障屏障”是集中发现问题的最高可用位置。它通常是生成新 goroutine 的地方(即:每个 http 接受)。在 ServeHTTP 方法中,您可能希望在不重新启动服务器的情况下捕获并记录单个恐慌(通常这种恐慌是微不足道的 nil ptr derefs)。您可能会在无法检查您需要知道的条件的地方看到恢复 - 例如文件句柄是否已经关闭。 (只需关闭并处理可能出现的恐慌)。

    我有一个大型代码库,只使用了 2 或 3 次恢复。它们仅适用于提到的情况,我这样做只是为了确保专门记录问题。即使我仍然要去 os.Exit 并让启动我的脚本重新启动我,我也会进行恢复以记录消息。

    【讨论】:

      猜你喜欢
      • 2015-04-29
      • 2015-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-20
      • 2015-09-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多