«Невозможно прочитать данные из транспортного соединения: существующее соединение было (НЕ принудительно) закрыто» при вызове веб-службы RESTful - PullRequest
0 голосов
/ 23 октября 2018

Я прочитал множество вопросов о переполнении стека (например, этот ), в которых обсуждались варианты следующего сообщения об ошибке:

System.Net.Http.HttpRequestException: ошибка при копированиисодержание в поток.---> System.IO.IOException: невозможно прочитать данные из транспортного соединения: существующее соединение было принудительно закрыто удаленным хостом.

Однако я получаю следующий вариант насообщение об ошибке:

System.Net.Http.HttpRequestException: Ошибка при копировании содержимого в поток.---> System.IO.IOException: Невозможно прочитать данные из транспортного соединения: существующее соединение было закрыто.

Нет указания «принудительно закрыто удаленным узлом»«.В сообщении об исключении нет более подробной информации о , почему было закрыто.

Почему это могло произойти?Означает ли это, что у меня был тайм-аут или что-то в этом роде, или это проблема со стороны нашего поставщика?(Я хотел бы убедиться, чья «ошибка» в том, что проблема заключается в том, что я собираю запрос у нашего поставщика для расследования).

Конкретный файл, который я загружаю, достаточно велик и может занять много времени.

Мой код довольно "стандартный" HttpClient логика "get":

    private async Task<string> GetReport(string fileNamePrefix, bool lookInCurrentFolder = false, bool returnEntireThing = true)
    {
        string fileName = $"{fileNamePrefix}-report-{DateTime.Now.ToString("yyyy-MM-dd")}.csv";

        string downloadFolder = FileUtilities.GetPath(KnownFolder.Downloads);

        string fileInDownloadFolder = Path.Combine(downloadFolder, fileName);

        if ((lookInCurrentFolder && !File.Exists(fileName)) || (!lookInCurrentFolder && !File.Exists(fileInDownloadFolder)))
        {
            HttpClient client = HttpClientConstructor.GetHttpClient(acceptVersion: false, acceptType: "text/csv");
            client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));

            using (HttpResponseMessage msg = await client.GetAsync("analytics/" + fileNamePrefix))
            {
                using (var fstr = new FileStream(lookInCurrentFolder ? fileName : fileInDownloadFolder, FileMode.Create))
                {
                    using (GZipStream str = new GZipStream(await msg.Content.ReadAsStreamAsync(), CompressionMode.Decompress))
                    {
                        str.CopyTo(fstr);
                    }
                }
            }
        }

        return returnEntireThing ? File.ReadAllText(lookInCurrentFolder ? fileName : fileInDownloadFolder) : (lookInCurrentFolder ? fileName : fileInDownloadFolder);
    }

Немного сокращенно, HttpClientConstructor - это фабрика, которая возвращает соответствующее HttpClientSingleton (поскольку Microsoft рекомендует использовать один HttpClient на протяжении всего жизненного цикла приложения).Возможно, будет несколько экземпляров HttpClient с несколькими различными конфигурациями acceptType.Экземпляры создаются примерно так:

           var client = new HttpClient
            {
                BaseAddress = new Uri("..."),
                Timeout = new TimeSpan(4, 0, 0)
            };

            client.DefaultRequestHeaders.Add("ApiToken", key);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(acceptType));

Что здесь не так?Почему странное сообщение об ошибке?Может ли это быть проблемой с моей стороны?

Редактировать: Я настраиваю параметры безопасности, как это, прежде чем создавать свои HttpClient экземпляры в HttpClientConstructor:

ServicePointManager.DefaultConnectionLimit = 8;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Кроме того, эта проблема периодически - код работает большую часть времени, я впервые вижу, как это происходит.

1 Ответ

0 голосов
/ 14 февраля 2019

У меня была похожая проблема с использованием общего HttpClient, подключающегося к серверу для вызовов REST.В результате возникла проблема с несоответствием тайм-аута KeepAlive на клиенте и сервере.Тайм-аут на стороне клиента задается параметром MaxServicePointIdleTime в ServicePointManager и по умолчанию равен 100 с.Тайм-аут простоя на стороне сервера был установлен на нашем сервере более коротким.

Сокращение времени ожидания на сервере по сравнению с клиентом приводило к тому, что сервер время от времени закрывал соединение, когда клиент пытался подключиться.Это привело к сообщаемому исключению.

Обратите внимание, что в конечном итоге я обнаружил проблему, потому что я также получил это исключение при тех же условиях:

System.Net.WebException: The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.

Хотя проблему можно исправить с помощью новогоHttpClient для каждого соединения с сервером, это идет вразрез с рекомендацией Microsoft о совместном использовании HttpClient.Я бы посоветовал установить для MaxServerPointIdleTime более короткое значение, возможно, 15 секунд, чтобы посмотреть, решит ли это проблему.Кроме того, если у вас есть доступ к коду сервера, вы можете найти его тайм-аут и попытаться установить для него значение, превышающее тайм-аут 100 с, установленный по умолчанию на клиенте.

...