Go中处理 `Context deadline exceeded`错误的方法

26,891 阅读2分钟

Context Deadline Exceeded是Go中发生的一个错误,当HTTP请求的上下文有一个截止时间超时设置,即请求应该在什么时间之后中止。如果服务器响应的时间大于设定的超时时间,则返回这个错误。在生产环境中,对请求设置超时是一个很好的做法,以确保你总是在有限的时间内得到一个响应(或错误)。

Context deadline exceeded 例子

package main
import (
"context"
"errors"
"log"
"net/http"
"os"
"time"
)
func slowServer(w http.ResponseWriter, r *http.Request) {
time.Sleep(10 * time.Second)
w.Write([]byte("Hello world!"))
}
func call() error {
client := &http.Client{}
req, err := http.NewRequest(http.MethodGet, "http://localhost:8080", nil)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(req.Context(), 1*time.Second)
defer cancel()
req = req.WithContext(ctx)
_, err = client.Do(req)
return err
}
func main() {
// run slow server
go func() {
http.HandleFunc("/", slowServer)
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}()
time.Sleep(1 * time.Second) // wait for server to run
// call server
err := call()
if errors.Is(err, context.DeadlineExceeded) {
log.Println("ContextDeadlineExceeded: true")
}
if os.IsTimeout(err) {
log.Println("IsTimeoutError: true")
}
if err != nil {
log.Fatal(err)
}
}

输出

2021/08/19 06:39:09 ContextDeadlineExceeded: true
2021/08/19 06:39:09 IsTimeoutError: true
2021/08/19 06:39:09 Get "http://localhost:8080": context deadline exceeded
exit status 1

在上面的例子中,我们:

  • 运行我们的慢速服务器,其任务是在10秒后返回一个响应
  • call() 函数中创建一个新的请求,这个请求将被发送到服务器上
  • 在这个请求上设置一个1秒的超时,即等待服务器响应后的时间值。
  • 将该请求发送到服务器

由于这个请求的超时时间被设置为1秒,而服务器在10秒后才响应,所以HTTP客户端会返回一个错误。

处理Context deadline exceeded 错误

当超过设定的超时时间时,HTTP客户端会返回 context.DeadlineExceeded错误。这个错误也可以用更通用的 os.IsTimeout()函数来处理,该函数检查错误是否已知,以报告超时的发生。

Context deadline exceeded (Client.Timeout exceeded while awaiting headers) 例子

超时不仅可以在单个HTTP请求的层面上设置,也可以在整个HTTP客户端的层面上设置。在这种情况下,这种客户端发出的每个请求都有相同的超时值。请看一个使用客户端超时选项的call() 函数的例子。

func call() error {
client := &http.Client{Timeout: 1 * time.Second}
_, err := client.Get("http://localhost:8080")
return err
}

输出

2021/08/19 07:35:14 IsTimeoutError: true
2021/08/19 07:35:14 Get "http://localhost:8080": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
exit status 1

在这种情况下,我们得到context deadline exceeded (Client.Timeout exceeded while awaiting headers) 错误。请注意,这不是一个 context.DeadlineExceeded错误的实例。