C# 控制台应用程序中的HttpClient.GetStringAsync阻塞

C# 控制台应用程序中的HttpClient.GetStringAsync阻塞,c#,dotnet-httpclient,C#,Dotnet Httpclient,我使用HttpClient编写了一个方法: private static async Task<string> DownloadString(string url) { var uri = new Uri(url); using (var client = new HttpClient()) { HttpRequestHeaders headers = client.DefaultRequestHeaders; headers

我使用
HttpClient
编写了一个方法:

private static async Task<string> DownloadString(string url)
{
    var uri = new Uri(url);

    using (var client = new HttpClient())
    {
        HttpRequestHeaders headers = client.DefaultRequestHeaders;
        headers.Accept.ParseAdd("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        headers.AcceptEncoding.ParseAdd("gzip, deflate");
        headers.AcceptLanguage.ParseAdd("en-US,en;q=0.5");
        headers.Connection.ParseAdd("keep-alive");
        headers.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0");
        headers.Host = uri.Host;

        return await client.GetStringAsync(uri).ConfigureAwait(false);
    }
}
如果我有互联网连接,或者它在我没有互联网连接的情况下运行(在这种情况下,它抛出一个异常),所有这些都可以正常工作。但是,如果我在下载时断开互联网,它就会挂在那里。没有例外。它只是挂着


有人能给我解释一下这里发生了什么事吗?我该如何解决这个问题呢?

我认为您必须使用HttpClient.Timeout属性

在HttpClient构造中,您可以使用:

var client = new HttpClient() 
{ 
    Timeout = TimeSpan.FromMilliseconds(200) 
};

最好将其从静态类更改为实例类,然后在单独的线程上运行。使用静态类和多线程时会遇到麻烦

其次,您为什么在这里调用ConfigureWait:

return await client.GetStringAsync(uri).ConfigureAwait(false);
您使用的是异步/等待模式,因此不需要使用它

当我试图定义它的时候,我发现它会在100秒后抛出

我在大约1秒钟后关闭了它

因此,没有bug/hang。
在Windows上,.Net使用底层的本机
WinHttp
API发出http请求

如果我们看一看,就会发现

private TimeSpan _connectTimeout = TimeSpan.FromSeconds(60);
private TimeSpan _sendTimeout = TimeSpan.FromSeconds(30);
private TimeSpan _receiveHeadersTimeout = TimeSpan.FromSeconds(30);
private TimeSpan _receiveDataTimeout = TimeSpan.FromSeconds(30);

如果您在请求开始后大约1秒阻止internet,则需要大约30~60秒才能触发超时。

看看这个答案@DavidHaim,在尝试定义它时,我发现它会在惊人的100秒后触发。@emperoaiman当您关闭interenet时,请求停止后大约过了多少秒?@DavidHaim我在大约1秒后关闭了它。http请求已经有了由.Net本身设置的默认超时。。这没有问题meaning@DavidHaim,看起来它默认为100秒。我不知道这么长…
configurewait
是最好的做法,如果我不想捕获同步上下文。。我怀疑使用实例方法是否有效。另外,如果它是异步的,为什么我要启动一个新线程呢?实际上是100秒<代码>默认值为100000毫秒(100秒)。
private TimeSpan _connectTimeout = TimeSpan.FromSeconds(60);
private TimeSpan _sendTimeout = TimeSpan.FromSeconds(30);
private TimeSpan _receiveHeadersTimeout = TimeSpan.FromSeconds(30);
private TimeSpan _receiveDataTimeout = TimeSpan.FromSeconds(30);