HttpClient.SendAsync在ASP.NET Core 2.0中运行时挂在对Socket.IO的协议升级GET请求调用上,但相同的代码在.NET 4.7上成功运行
我构建了一个包含所有Socket.IO握手逻辑的类(我使用Chrome开发人员工具和Wireshark进行了反向工程)。在使用.NET 4.7和GTK#构建的测试GUI应用程序中运行时,此类成功完成了一次握手(并且可以成功发送emit()
条消息),但是在ASP.NET Core中运行时,该类挂起了protocol upgrade
GET请求2。
请注意,握手的前两个步骤起作用,它们还使用HttpClient
(获取会话ID,选择room
(命名空间)。第三次调用失败,仅在ASP.NET中Core 2 (请参见下面的代码)。最后,我在.NET 4.7应用程序和ASP.NET Core 2中在所有调用中都使用了 same HttpClient
实例(我建立了一个名为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;
}
}
我逐步完成了Socket.IO中的握手JS代码,可以看到它接受了协议升级。它返回一个成功的确认(返回Sec-Websocket-Accept
头),但是HttpClient.SendAsync坐在那里挂了(我也看到Wireshark也返回了这个头。Socket.IO最终关闭了套接字,因为这种挂起会导致{ {1}}。当插座强制关闭时,ping timeout
会“松开”并继续。
同样,此问题的关键是在.NET 4.7中运行时,它工作正常(即使我构建的类位于dotnet标准2.0项目中!)
我已验证自己“一直向下同步”。我实际上有一个SendAsync()
在ASP.NET Core 2中运行,可以异步启动此连接。