具有无限超时的HttpClient会抛出超时异常 [英] HttpClient with infinite time out throws time out exception

查看:192
本文介绍了具有无限超时的HttpClient会抛出超时异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的HttpClient使用摘要式身份验证连接到服务器,并期待搜索查询。这些搜索查询可以随时进入,因此客户应始终保持连接处于打开状态。

My HttpClient uses digest authentication to connect to the server and expects search queries in response. These search queries can come in any time so the client is expected to leave the connection open at all times.

使用以下代码建立连接:

The connection is made using the following code:

public static async void ListenForSearchQueries(int resourceId)
{
    var url = $"xxx/yyy/{resourceId}/waitForSearchRequest?token=abc";

    var httpHandler = new HttpClientHandler { PreAuthenticate = true };

    using (var digestAuthMessageHandler = new DigestAuthMessageHandler(httpHandler, "user", "password"))
    using (var client = new HttpClient(digestAuthMessageHandler))
    {
        client.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite);

        var request = new HttpRequestMessage(HttpMethod.Get, url);

        var tokenSource = new CancellationTokenSource();
            tokenSource.CancelAfter(TimeSpan.FromMilliseconds(Timeout.Infinite));

        using (var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, tokenSource.Token))
        {
            Console.WriteLine("\nResponse code: " + response.StatusCode);

            using (var body = await response.Content.ReadAsStreamAsync())
            using (var reader = new StreamReader(body))
                while (!reader.EndOfStream)
                    Console.WriteLine(reader.ReadLine());
         }
    }
}

这是方法的方法在控制台应用程序的Main方法中使用。

This is how the method is being used in the Main method of a console application.

private static void Main(string[] args)
{
   const int serviceId = 128;
   .
   .
   .
   ListenForSearchQueries(resourceId);
   Console.ReadKey();
}

这是控制台窗口上的输出:

This is what the output on the console window looks like:

Response code: OK
--searchRequestBoundary

即使客户端的超时设置为无穷大,连接在第一次输出后大约五分钟(这不是HttpClient的默认超时)后超时,抛出以下异常。

Even though the timeout for the client is set to infinity, the connection times out after roughly five minutes (which is not the default timeout of the HttpClient) after the first output, throwing the following exception.

System.IO.IOException occurred
  HResult=0x80131620
  Message=The read operation failed, see inner exception.
  Source=System.Net.Http
  StackTrace:
   at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.Net.Http.DelegatingStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.IO.StreamReader.ReadBuffer()
   at System.IO.StreamReader.get_EndOfStream()
   at ConsoleTester.Program.<ListenSearchQueriesDigestAuthMessageHandler>d__10.MoveNext() in C:\Users\xyz\ProjName\ConsoleTester\Program.cs:line 270

Inner Exception 1:
WebException: The operation has timed out.

用于身份验证的DelegateHandler是对这个代码(参见源代码部分)。

The DelegateHandler used for the authentication is a a rough adaption of this code (see the source section).

为什么客户端超时以及如何我可以阻止这种情况吗?

Why is the client timing out and how can I prevent this?

我的最终目标是打个电话并无限期地等待回应。当响应确实到来时,我不希望关闭连接,因为将来可能会有更多响应。不幸的是,我无法在服务器端更改任何内容。

My ultimate goal is to make a call and wait indefinitely for a response. When a response does come, I don't want the connection to close because more responses might come in the future. Unfortunately, I can't change anything at the server end.

推荐答案

虽然 Stream的默认值.CanTimeout 为false ,通过 response.Content.ReadAsStreamAsync()返回一个流给出一个CanTimeout属性返回true的流。

Although the default value for Stream.CanTimeout is false, returning a stream via the response.Content.ReadAsStreamAsync() gives a stream where the CanTimeout property returns true.

此流的默认读写超时是5分钟。这是在五分钟不活动之后,流将抛出异常。与问题中显示的异常非常相似。

The default read and write time out for this stream is 5 minutes. That is after five minutes of inactivity, the stream will throw an exception. Much similar to the exception shown in the question.

要更改此行为,可以调整流的ReadTimeout和/或WriteTimeout属性。

To change this behavior, ReadTimeout and/or the WriteTimeout property of the stream can be adjusted.

以下是 ListenForSearchQueries 方法的修改版本,它将ReadTimeout更改为无限。

Below is the modified version of the ListenForSearchQueries method that changes the ReadTimeout to Infinite.

public static async void ListenForSearchQueries(int resourceId)
{
    var url = $"xxx/yyy/{resourceId}/waitForSearchRequest?token=abc";

    var httpHandler = new HttpClientHandler { PreAuthenticate = true };

    using (var digestAuthMessageHandler = new DigestAuthMessageHandler(httpHandler, "user", "password"))
    using (var client = new HttpClient(digestAuthMessageHandler))
    {
        client.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite);

        var request = new HttpRequestMessage(HttpMethod.Get, url);

        var tokenSource = new CancellationTokenSource();
            tokenSource.CancelAfter(TimeSpan.FromMilliseconds(Timeout.Infinite));

        using (var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, tokenSource.Token))
        {
            Console.WriteLine("\nResponse code: " + response.StatusCode);

            using (var body = await response.Content.ReadAsStreamAsync())
            {
                body.ReadTimeout = Timeout.Infinite;

                using (var reader = new StreamReader(body))
                    while (!reader.EndOfStream)
                        Console.WriteLine(reader.ReadLine());
            }
         }
    }
}

这个修复了实际被流抛出的异常,但似乎被HttpClient抛出了。

This fixed the exception which was actually being thrown by the stream but seemed like was being thrown by the HttpClient.

这篇关于具有无限超时的HttpClient会抛出超时异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆