我有一些用 Go 编写的代码(见下文),应该“扇出”HTTP 请求,并整理/聚合详细信息。
我是 golang 新手,所以希望我是个菜鸟,而且我的知识有限
程序的输出当前类似于:
{
"Status":"success",
"Components":[
{"Id":"foo","Status":200,"Body":"..."},
{"Id":"bar","Status":200,"Body":"..."},
{"Id":"baz","Status":404,"Body":"..."},
...
]
}
有一个本地服务器故意运行缓慢(休眠 5 秒,然后返回响应)。但我列出了其他网站(请参阅下面的代码),有时也会触发错误(如果它们出错,那就很好)。
我目前遇到的问题是如何最好地处理这些错误,特别是“超时”相关的错误;因为我不确定如何识别失败是超时还是其他错误?
目前我总是收到一揽子错误:
Get http://localhost:8080/pugs: read tcp 127.0.0.1:8080: use of closed network connection
其中
http://localhost:8080/pugs
通常是失败的 url(希望是超时!)。但正如您从代码(下面)中看到的,我不确定如何确定错误代码与超时相关,也不知道如何访问响应的状态代码(我目前只是将其设置为404
但显然这是不对的 - 如果服务器出错,我会期望类似 500
状态代码之类的内容,显然我想在我发回的聚合响应中反映这一点)。
完整代码如下。任何帮助表示赞赏。
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\n", 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\n", 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\n", err)
return
}
fmt.Println(string(j))
}
我添加此内容是为了完成,因为正确的答案是由 Dave C 在已接受答案的评论中提供的。
我们可以检查错误是否是或包含a
net.Error
并检查是否超时。
resp, err := client.Get(url)
if err != nil {
// if there is an error check if its a timeout error
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
// handle timeout
return
}
// otherwise handle other types of error
}
如果您想扇出然后聚合结果,并且您想要 net/http 包未提供的特定超时行为,那么您可能需要使用 goroutine 和通道。
我今天刚刚观看了这个视频,它将引导您使用 Go 的并发功能完成这些场景。另外,演讲者 Rob Pike 非常权威——他解释得比我好得多。
Go 1.5 版本通过更具体地说明其处理的错误类型解决了这个问题。
因此,如果您看到此示例https://github.com/Integralist/Go-Requester/blob/master/requester.go#L38,您会发现我能够将正则表达式模式应用于错误消息破译错误是否确实是超时
status := checkError(err.Error())
func checkError(msg string) int {
timeout, _ := regexp.MatchString("Timeout", msg)
if timeout {
return 408
}
return 500
}