Go语言 HTTP客户端:无网络时超时更快

c9qzyr3d  于 2023-05-27  发布在  Go
关注(0)|答案(2)|浏览(228)

当在Go中发出http Get请求时,它会在返回错误之前等待完整的超时时间,即使没有网络连接。
我认为在内部,它很快就知道它失败了;我希望错误尽快传播,而不是等待超时时间。我确实希望它尝试20秒时,网络在那里,只是慢。如何设置具有此行为的客户端?
查看问题的代码:

var client = &http.Client{
    Timeout: time.Second * 20,
}

response, err := client.Get(url)

如果重要的话,我正在使用gomobile,它在iOS模拟器上运行。

bvjveswy

bvjveswy1#

如果没有连接的网络接口,初始TCP握手将失败,此时没有成功的机会。接下来的19.99秒它在做什么?
Go语言的HTTP客户端在没有网络连接时会等待整个超时时间,然后返回错误,因为客户端在发起请求时不知道网络的状态。它只知道在指定的超时时间内没有收到响应。
当客户端无法建立连接时,客户端正在等待操作系统的TCP堆栈返回错误,由于网络配置、操作系统的TCP/IP实现等各种因素,这可能需要一些时间。
我不知道有什么直接的方法可以在Go的HTTP客户端没有网络连接的情况下设置更快的超时。
另一种方法是将上下文与超时和检查网络连接状态的单独goroutine结合使用。如果goroutine检测到没有网络连接,它会取消上下文。
请求将使用NewRequestWithContext
例如:

ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()

// Check network connection in a separate goroutine.
go func() {
    if !isNetworkAvailable() {
        cancel()
    }
}()

req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
    log.Fatal(err)
}

response, err := client.Do(req)
if err != nil {
    log.Fatal(err)
}

你需要实现isNetworkAvailable():检查是否存在可用的网络连接的功能。这可能是特定于平台的,在iOS上,您可能需要使用系统API来检查网络状态。
请注意,这种方法可能无法在所有场景中完美工作。例如,网络可以在isNetworkAvailable()检查之后,但在HTTP请求发出之前变得可用。在这种情况下,即使网络可用,请求也将被取消。但在已知网络在较长时间内不可用的情况下,它可能会有所帮助。
例如:

import (
    "net"
    "time"
)

func isNetworkAvailable() bool {
    timeout := 2 * time.Second
    conn, err := net.DialTimeout("tcp", "8.8.8.8:53", timeout)
    if err != nil {
        return false
    }
    if conn != nil {
        defer conn.Close()
    }
    return true
}

此函数尝试8.8.8.8在端口53(DNS服务器使用的端口)上建立到www.example.com的TCP连接,超时时间为2秒。
(as JimB在评论中添加:“您所能做的就是尝试使用较短的超时进行一些网络呼叫”)
如果函数在这段时间内无法建立连接,则假定没有网络连接并返回false。
如果可以建立连接,则关闭连接并返回true。

azpvetkf

azpvetkf2#

这里的答案很简单:Golang内部能够并且确实知道何时没有网络,并且及时地向上传播故障,而不等待20 s超时。没有任何东西通过网络发送,也没有什么需要等待的。Go似乎可以正确地完成所有事情,并且不需要对示例代码进行任何更改。
该问题仍然持续重现,但仅在iOS模拟器上。这似乎是一个特定于iOS模拟器如何将连接Map到主机操作系统的问题。不确定这是一个长期存在的问题,还是我的MacOS/模拟器配对上的一次性问题。在主机MacOS和真实的的iOS设备上,它可以正常工作,在没有网络接口的情况下立即超时。
不需要额外的请求,因为这只是通往相同结论的另一条路径,这增加了其他失败的可能性。这可能有助于区分网络问题和特定服务的问题,或者更快地获得真实的网络状态(已连接网络接口的存在)的指示器。

相关问题