如何检查错误是否为“超过最后期限”错误?

时间:2019-05-11 01:04:24

标签: go

我发送的请求的上下文指定了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功能?

2 个答案:

答案 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))