Go HTTP客户端超时与上下文超时的区别

19

http.Client设置的超时时间和请求上下文中设置的超时时间有什么区别?

我看到过两种在http client中设置超时时间的方法。

第一种:

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://localhost:8080", nil)

其次:

client := http.Client{
    Timeout: 2 * time.Second,
}
resp, err := client.Do(req)
if err != nil {
    panic(err)
}

何时使用其中之一而不是另一个?


超时字段早于上下文,适用于客户端发出的所有请求。 - Peter
2个回答

20

两者都能实现同样的目标,即由于超时而终止请求。

但使用上下文是首选方式,因为它专为此任务而设计。在Go添加上下文之前,timeout字段就存在了。在创建请求时,您必须选择一个超时时间,因为请求将选择应用较小的超时时间,使其他超时时间无效。在这种情况下,首选方法是使用上下文超时,因为您对其具有更多的控制权,您可以在不指定超时时间的情况下使用取消来取消请求。使用上下文,您还可以通过其中传递任何值来描述请求范围值。

使用上下文是针对请求特定的,而使用Client超时可能会应用于传递给Do方法的所有请求客户端。如果您想将截止日期/超时时间专业化到每个请求中,请使用上下文;否则,如果您希望所有出站请求都有1个超时时间,则仅使用客户端超时即可。

您也可以在此处阅读相关信息:Specify timeout when tracing HTTP request in Go


3
通常我们只在希望为HTTP请求设置超时时才会使用这种方法。
client := http.Client{
    Timeout: 2 * time.Second,
}
resp, err := client.Do(req)
if err != nil {
    panic(err)
}

我认为问题在于我们何时应该使用上下文,如果您查看文档,您会发现:
包context定义了Context类型,它携带截止时间、取消信号和其他请求范围的值跨越API边界和进程之间。
假设您有一个需要在某个时间内响应的API,并且您需要一种方法来跟踪它创建的所有go例程,并希望同时向它们发送停止信号。这是使用上下文并将其传递给由一个API调用创建的所有go例程的用例,这样很容易知道上下文何时过期以及何时需要停止工作。
虽然进行http请求的方式可以工作,但是创建一个特定于特定请求的上下文并不是很有意义,除非您的请求在goroutine中运行,并且由于执行后收到了一些其他输入而需要传递取消信号。
在大多数情况下,理想情况下,上下文用于限定您需要发出信号的一系列请求/ goroutines。
您应该阅读此内容以获取更清晰的上下文使用时机: https://blog.golang.org/context

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接