我正在发送一个带有 10 秒超时指定的上下文的请求:
ctx, cancel := context.WithTimeout(context.Background(), time.Second * 10)
defer cancel()
_, err := client.SendRequest(ctx)
if err != nil {
return 0, err
}
Run Code Online (Sandbox Code Playgroud)
现在,当我达到超时时,错误消息令人困惑:
超出上下文截止日期
是否可以检查 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
}
Run Code Online (Sandbox Code Playgroud)
如何实现这样的isTimeoutError
功能?
Dir*_*aio 17
在 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))
Run Code Online (Sandbox Code Playgroud)
您可以通过将错误与context.DeadlineExceeded进行比较来确定错误是否是上下文超时的结果:
if err == context.DeadlineExceeded {
// context deadline exceeded
}
Run Code Online (Sandbox Code Playgroud)
您可以使用以下函数确定错误是否是任何超时错误:
func isTimeoutError(err error) bool {
e, ok := err.(net.Error)
return ok && e.Timeout()
}
Run Code Online (Sandbox Code Playgroud)
此函数返回 true 所有超时错误,包括 value context.DeadlineExceeded
。该值满足net.Error
接口并具有Timeout
始终返回的方法true
。