我有一些用Go编写的代码(见下文),该代码应该"散布" HTTP请求,并整理/聚合详细信息。
I'm new to golang and so expect me to be a nOOb and my knowledge to be limited
程序的输出当前类似于:
1 2 3 4 5 6 7 8 9 | { "Status":"success", "Components":[ {"Id":"foo","Status":200,"Body":"..."}, {"Id":"bar","Status":200,"Body":"..."}, {"Id":"baz","Status":404,"Body":"..."}, ... ] } |
有一个本地服务器正在运行,该服务器故意过慢(睡眠5秒钟,然后返回响应)。但是我列出了其他站点(请参见下面的代码),它们有时也会触发错误(如果它们出错,那就很好了)。
我目前遇到的问题是如何最好地处理这些错误,尤其是与"超时"相关的错误。因为我不确定如何识别失败是超时还是其他错误?
此刻,我一直都返回错误消息:
1 | Get http://localhost:8080/pugs: read tcp 127.0.0.1:8080: use of closed network connection |
其中
完整的代码可以在下面看到。任何帮助表示赞赏。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | package main import ( "encoding/json" "fmt" "io/ioutil" "net/http" "sync" "time" ) type Component struct { Id string `json:"id"` Url string `json:"url"` } type ComponentsList struct { Components []Component `json:"components"` } type ComponentResponse struct { Id string Status int Body string } type Result struct { Status string Components []ComponentResponse } var overallStatus string ="success" func main() { var cr []ComponentResponse var c ComponentsList b := []byte(`{"components":[{"id":"local","url":"http://localhost:8080/pugs"},{"id":"google","url":"http://google.com/"},{"id":"integralist","url":"http://integralist.co.uk/"},{"id":"sloooow","url":"http://stevesouders.com/cuzillion/?c0=hj1hfff30_5_f&t=1439194716962"}]}`) json.Unmarshal(b, &c) var wg sync.WaitGroup timeout := time.Duration(1 * time.Second) client := http.Client{ Timeout: timeout, } for i, v := range c.Components { wg.Add(1) go func(i int, v Component) { defer wg.Done() resp, err := client.Get(v.Url) if err != nil { fmt.Printf("Problem getting the response: %s\ ", err) cr = append(cr, ComponentResponse{ v.Id, 404, err.Error(), }) } else { defer resp.Body.Close() contents, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Printf("Problem reading the body: %s\ ", err) } cr = append(cr, ComponentResponse{ v.Id, resp.StatusCode, string(contents), }) } }(i, v) } wg.Wait() j, err := json.Marshal(Result{overallStatus, cr}) if err != nil { fmt.Printf("Problem converting to JSON: %s\ ", err) return } fmt.Println(string(j)) } |
-
最有可能与您的问题无关,但是您将数据竞争附加到
cr 。 如果没有同步,则无法从多个goroutine中写入相同的变量。 您可能要使用种族探测器来构建/运行。 - 感谢您的评论。 我将寻找利用渠道来代替+虐待调查该种族探测器:-)
- 如果客户端调用返回错误,则没有状态代码,因为没有完整的http请求。 那时您没有太多可以做的错误,但是在go1.5中,client.Timeout至少会在net.Error中返回更好的消息。
- 请问有帮助吗?
- 似乎1.5的发布日期已过期(截至2015年8月17日)。 病态必须坚持下去,看看是否确实可以解决问题。
如果您想散开然后汇总结果,并且想要net / http软件包没有给您的特定超时行为,那么您可能要使用goroutine和通道。
我今天刚刚看了这段视频,它将通过Go的并发功能向您详细介绍这些场景。 另外,发言人罗伯·派克(Rob Pike)很有权威-他的解释比我能做的更好。
https://www.youtube.com/watch?v=f6kdp27TYZs
- downvote用于发布一个小时的视频。答案在哪里?
Go 1.5版本通过更具体地处理错误类型来解决此问题。
因此,如果您看到此示例https://github.com/Integralist/Go-Requester/blob/master/requester.go#L38,您将看到我可以将正则表达式模式应用于错误消息以解密是否 错误的确是超时
1 2 3 4 5 6 7 8 9 10 11 | status := checkError(err.Error()) func checkError(msg string) int { timeout, _ := regexp.MatchString("Timeout", msg) if timeout { return 408 } return 500 } |
-
最好不要在错误字符串中四处张望,它是令人难以置信的脆弱。错误字符串不属于任何API。
net.Error 接口为此定义了Timeout 方法。 - @Dave C感谢您的评论,但我不确定您的建议如何工作。我从client.Get返回的错误是一个字符串。它没有方法。没什么可查询的
-
它不仅是字符串,而且是
error 。通过使用err.Error() 调用check函数,可以遍历除格式化结果字符串以外的所有内容。相反,您应该尝试类型声明和其他检查。仅当所有方法均无效时,您才可以:a)提交有关不可测试错误的错误报告,以及b)作为丑陋的解决方法(带有大的警告注释),可以在字符串中使用grep(或更改您调用的代码)返回可测试的错误,并将其作为更改请求提交给上游)。 -
顺便说一句,我终于开始尝试类型断言检查(
err.(net.Error) ),似乎错误的类型是* url.Error而不是net.Error,所以我不能使用该; panic: interface conversion: *url.Error is not net.Error: missing method Temporary -
url.Error 包含一个带有基本错误(如果有)的Err error 字段。它几乎还专门用于URL解析错误,在这种情况下,它永远不会超时。 (例如,类似if e, ok := err.(net.Error); ok && e.Timeout() {*…network timeout…*} 之类的东西会正确地说出它不是与网络超时相关的错误。)