我发送的请求的上下文指定了10秒的超时时间:
ctx, cancel := context.WithTimeout(context.Background(), time.Second * 10)
defer cancel()
_, err := client.SendRequest(ctx)
if err != nil {
return 0, err
}
现在当我达到该超时时间时,错误消息令人困惑:
上下文截止日期已结束
是否可以检查err是否是超时错误,以便我可以打印更好的错误消息?
ctx, cancel := context.WithTimeout(context.Background(), time.Second * 10)
defer cancel()
_, err := client.SendRequest(ctx)
if err != nil {
if isTimeoutError(err) {
return nil, fmt.Errorf("the request is timeout after 10 seconds")
}
return nil, err
}
如何实现这种isTimeoutError
功能?
答案 0 :(得分:3)
您可以通过将错误与context.DeadlineExceeded进行比较来确定错误是否是上下文超时的结果:
if err == context.DeadlineExceeded {
// context deadline exceeded
}
您可以使用以下函数来确定错误是否为超时错误:
func isTimeoutError(err error) bool {
e, ok := err.(net.Error)
return ok && e.Timeout()
}
此函数返回所有超时错误,包括值context.DeadlineExceeded
为true。该值满足net.Error
接口,并且具有一个Timeout
方法,该方法始终返回true
。
答案 1 :(得分:2)
在Go 1.13+中最干净的方法是使用新的errors.Is
函数。
// Create a context with a very short timeout
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
defer cancel()
// Create the request with it
r, _ := http.NewRequest("GET", "http://example.com", nil)
r = r.WithContext(ctx)
// Do it, it will fail because the request will take longer than 1ms
_, err := http.DefaultClient.Do(r)
log.Println(err) // Get http://example.com: context deadline exceeded
// This prints false, because the http client wraps the context.DeadlineExceeded
// error into another one with extra information.
log.Println(err == context.DeadlineExceeded)
// This prints true, because errors.Is checks all the errors in the wrap chain,
// and returns true if any of them matches.
log.Println(errors.Is(err, context.DeadlineExceeded))