我有一个部署在Google Cloud上的网站。该网站使用asp.net core(v2.2)和signalr编写。
我的应用程序体系结构是我有两台运行Linux的计算机,服务于同一站点。该站点由Kastrel(localhost)提供服务,并由nginx包装(用于外部网络)。我有云负载均衡器,它在这两个实例之间分配流量。 LB定义为按会话亲和力划分流量。
我定义SignalR以使用Redis,以便在多个实例环境中正常工作。
我的startup.cs
代码:
var redisCs = ConfigurationOptions.Parse("REDIS CS");
services.AddSignalR().AddRedis(options =>
{
options.ConnectionFactory = async writer =>
{
var connection = await ConnectionMultiplexer.ConnectAsync(redisCs, writer);
return connection;
};
options.Configuration.ClientName = "Main-website-Signalr";
});
当我对其进行测试时,有时它可以工作,而有时却不能。
失败时,我会在浏览器控制台上看到以下日志:
WebSocket connection to 'wss://mysite.com/hubs/myhub?id=R_Zmaew-lRN_r2d_c-xOyg' failed: Error during WebSocket handshake: Unexpected response code: 404
在浏览器的“网络”选项卡上,我看到浏览器尝试与地址wss://mysite.com/hubs/myhub?id=R_Zmaew-lRN_r2d_c-xOyg
通信并获得404响应。
我担心Nginx会以某种方式阻止连接,所以我决定在没有任何中介的情况下与Kestrel连接。我进入了计算机并运行以下命令:
$ curl 127.0.0.1:5000/hubs/businesses?id=Tta4PmrjMrzHBHa8CT0SPQ -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /hubs/myhub?id=Tta4PmrjMrzHBHa8CT0SPQ HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Date: Wed, 05 Jun 2019 06:26:09 GMT
< Content-Type: text/plain
< Transfer-Encoding: chunked
<
* Curl_http_done: called premature == 0
* Connection #0 to host 127.0.0.1 left intact
No Connection with that ID
因此,我收到404错误-与从浏览器获得的错误相同。我猜现在没有人以某种方式阻止连接。 SignalR配置已损坏。
SignalR为什么可以找到连接?
我登录的机器是否重要?连接不是通过Redis通过的吗?
答案 0 :(得分:0)
当单个负载均衡器后面有多个服务器实例时,您需要启用粘性会话,这意味着唯一的客户端将只能连接到一台计算机。
您可以在https://docs.microsoft.com/en-us/aspnet/core/signalr/scale?view=aspnetcore-2.2#redis-backplane
中看到有关Redis背板的一些信息。SignalR是一个协议,该协议的一部分意味着在“协商”期间将在服务器上创建连接ID。这意味着您不能随便用ID随机卷曲端点,因为curl无法理解SignalR协议。
如果您对https://github.com/aspnet/AspNetCore/tree/master/src/SignalR/docs/specs感兴趣,可以阅读有关该协议的更多信息