HttpClient.SendAsync зависает, разговаривая с Socket.IO - PullRequest
0 голосов
/ 07 января 2019

HttpClient.SendAsync зависает при вызове GET-запроса на обновление протокола при работе в ASP.NET Core 2.0, но тот же код успешно работает в .NET 4.7

.

Я создал класс, который имеет всю логику рукопожатия Socket.IO (я реверсировал ее, используя комбинацию инструментов разработчика Chrome и Wireshark). Этот класс успешно завершает рукопожатие при запуске в тестовом приложении с графическим интерфейсом, созданным с использованием .NET 4.7 и GTK # (и может успешно emit() сообщения), но зависает при запросе protocol upgrade GET при работе в ASP.NET Core 2.

Обратите внимание, что первые два шага в рукопожатии работают, и они также используют HttpClient (получить идентификатор сеанса, выберите room (пространство имен). 3-й вызов не выполняется, только в ASP.NET Core 2 (см. код ниже). Наконец, я использую один и тот же HttpClient экземпляр для всех вызовов, как в приложении .NET 4.7, так и в ASP.NET Core 2 (я создал класс под названием SocketMediator и я использую этот точный класс в обоих местах).

URL-адрес, который я использую для запроса на обновление протокола: "http://127.0.0.1:7200/socket.io/?EIO=3&transport=polling&t=1546875159&sid=cD5KhP_8FKPV-ojhAAAA" sid предоставляется при первом вызове, а t является сгенерированной меткой времени.

using (var protocolUpgradeRequest = new HttpRequestMessage(HttpMethod.Get, probeTURl))
        {
            protocolUpgradeRequest.Headers.Add("DNT", "1");
            protocolUpgradeRequest.Headers.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3642.0 Safari/537.36");
            protocolUpgradeRequest.Headers.Add("Cookie", $"io={sessionId}");
            protocolUpgradeRequest.Headers.Add("Connection", "Upgrade");
            protocolUpgradeRequest.Headers.Add("Pragma", "no-cache");
            protocolUpgradeRequest.Headers.Add("Cache-control", "no-cache");
            protocolUpgradeRequest.Headers.Add("Upgrade", "websocket");
            protocolUpgradeRequest.Headers.Add("Sec-Websocket-Version", "13");
            protocolUpgradeRequest.Headers.Add("Accept-Encoding", "gzip, deflate, br");
            protocolUpgradeRequest.Headers.Add("Sec-Websocket-Key", websocketKey);
            protocolUpgradeRequest.Headers.Add("Sec-Websocket-Extensions", "permessage-deflate; client_max_window_bits");

            try
            {
                using (var response = await httpClient.SendAsync(protocolUpgradeRequest, CancellationToken.None))
                {
                    if (response.StatusCode != HttpStatusCode.SwitchingProtocols)
                    {
                        throw new HttpRequestException(
                            "Did not correctly receive protocol switch from server!");
                    }

                    var accept = response.Headers.GetValues("Sec-Websocket-Accept");

                    if (!accept.Any())
                    {
                        throw new HttpRequestException("Did not get Sec-Websocket-Accept header!");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex);
                throw ex;
            }
        }

Я прошёл JS-код рукопожатия в Socket.IO и вижу, что он принимает обновление протокола. Он возвращает успешное подтверждение (возвращается заголовок Sec-Websocket-Accept), но HttpClient.SendAsync сидит там зависшим (я вижу, что этот заголовок также возвращается с Wireshark. Socket.IO в конечном итоге закрывает сокет, потому что это зависание вызывает ping timeout Когда гнездо закрыто принудительно, именно тогда SendAsync() «развязывается» и продолжается.

Опять же, ключ к этой проблеме в том, что она прекрасно работает при работе в .NET 4.7 (даже если созданный мной класс живет в проекте стандарта dotnet 2.0!)

Я подтвердил, что я "полностью асинхронен". У меня на самом деле BackgroundService работает в ASP.NET Core 2, который инициирует это соединение асинхронно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...