golang中context超时的一个例子
有时我们会利用 golang 去调用第三方接口,我们会像下面这样写:
package main
import (
"io/ioutil"
"log"
"net/http"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "http://httpbin.org/get", nil)
if err != nil {
log.Fatal(err)
}
c := &http.Client{}
res, err := c.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
out, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}
log.Println(string(out))
}
但是有时接口会因为某些原因,比如请求 MySQL 等,导致接口请求时间过长。所以我们希望接口在规定时间内就返回,比如 80 毫秒。如果接口 80 毫秒没有返回,我们会利用上下问的**context.WithTimeout**让接口超时返回。
我们需要修改代码像下面这样:
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*80))
defer cancel()
req = req.WithContext(ctx)
我们首先定义一个指定超时的新上下文(使用 time.Duration)。 然后,我们使用 WithContext 将上下文添加到我们的请求中。 当创建带有超时的新上下文时,我们会收到一个 CancelFunc,它用于在上下文过期后清理资源。 这是有关 CancelFunc 的更多信息
调用 CancelFunc 会取消子项及其子项,删除父项对子项的引用,并停止任何关联的计时器。 调用 CancelFunc 失败会泄漏子项及其子项,直到父项被取消或计时器触发。 go vet 工具检查是否在所有控制流路径上使用了 CancelFuncs。
或者你也可以直接定义一个带有上下文的 request:
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*80))
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://httpbin.org/get", nil)
下面是完整示例:
package main
import (
"context"
"io/ioutil"
"log"
"net/http"
"time"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "http://httpbin.org/get", nil)
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*80)
defer cancel()
req = req.WithContext(ctx)
c := &http.Client{}
res, err := c.Do(req)
if err != nil {
log.Fatal("request err:", err)
}
defer res.Body.Close()
out, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}
log.Println(string(out))
}