SignalR 在 F5 后面带有 Redis 背板 - 状态代码:400,原因短语:“错误请求”

本文关键字:短语 错误请求 请求 错误 代码 F5 状态 背板 Redis SignalR | 更新日期: 2023-09-27 18:30:16

我在Server 2012 R2上使用SignalR.Redis 2.1.2的SignalR.Redis 2.1.2,IIS 8.5启用了WebSockets。

一切都在我的开发环境中完美运行。我甚至可以在配置为使用相同背板的站点的不同服务器上(例如http machine1/myapp/signalr,http machine2/myapp/signalr)上建立副本,并且两个UI都可以完美地向他们发布消息。

然后,我将"myapp"移动到下一个环境,这是一个由 2 台计算机组成的集群,位于 F5 负载均衡器后面,使用 dns 别名设置路由到 F5,然后循环"myapp"。网站本身可以很好地连接到信号器,并且可以接收它订阅的已发布消息,但是当我尝试通过别名(例如 http myappalias/signalr)发布到网站时,我收到 400,错误请求错误响应。下面是错误的示例。

  InnerException: Microsoft.AspNet.SignalR.Client.Infrastructure.StartException
       _HResult=-2146233088
       _message=Error during start request. Stopping the connection.
       HResult=-2146233088
       IsTransient=false
       Message=Error during start request. Stopping the connection.
       InnerException: System.AggregateException
            _HResult=-2146233088
            _message=One or more errors occurred.
            HResult=-2146233088
            IsTransient=false
            Message=One or more errors occurred.
            InnerException: Microsoft.AspNet.SignalR.Client.HttpClientException
                 _HResult=-2146233088
                 _message=StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Pragma: no-cache
  Transfer-Encoding: chunked
  X-Content-Type-Options: nosniff
  Persistent-Auth: true
  Cache-Control: no-cache
  Date: Thu, 13 Nov 2014 22:30:22 GMT
  Server: Microsoft-IIS/8.5
  X-AspNet-Version: 4.0.30319
  X-Powered-By: ASP.NET
  Content-Type: text/html
  Expires: -1
}

以下是我用来将测试消息发布到每个环境的一些测试代码,在"连接"上失败。开始()。等等()"

class Program
{
    static void Main(string[] args)
    {
        var connection = new HubConnection("http://myappalias/signalr");
        connection.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
        var proxy = connection.CreateHubProxy("MyAppHub");
        connection.Start().Wait();
        ConsoleKeyInfo key = Console.ReadKey();
        do
        {

            proxy.Invoke("NewMessage", new Message() { Payload = "Hello" });
            Console.WriteLine("Message fired.");
            key = Console.ReadKey();
        } while (key.Key != ConsoleKey.Escape);
    }
}

现在,如果我不使用"myappalias",而是正面撞击服务器,它可以完美运行。看起来要么是 F5 的问题,要么是需要针对这种情况对客户端进行不同的配置,要么是在设置 signlar 的启动类时我必须做一些不同的事情。这是我正在使用的启动类的示例。

[assembly: OwinStartup(typeof(MyApp.Startup))]
namespace MyApp
{
    public class Startup
    {
        private static readonly ILog log = LogManager.GetLogger
        (System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        public void Configuration(IAppBuilder app)
        {
            try
            {
                log.Debug(LoggingConstants.Begin);
                string redisServer = ConfigurationManager.AppSettings["redis:server"];
                int redisPort = Convert.ToInt32(ConfigurationManager.AppSettings["redis:port"]);
                HubConfiguration configuration = new HubConfiguration();
                configuration.EnableDetailedErrors = true;
                configuration.EnableJavaScriptProxies = false;
                configuration.Resolver = GlobalHost.DependencyResolver.UseRedis(redisServer, redisPort, string.Empty, "MyApp");
                app.MapSignalR("/signalr", configuration);   
                log.Info("SIGNALR - Startup Complete");
            }
            finally
            {
                log.Debug(LoggingConstants.End);
            }
        }
    }
}

我下载了客户端源代码,并直接将其连接而不是 nuget 包,这样我就可以逐步完成所有操作。我似乎它成功地协商,然后尝试与 SSE 和 LongPolling 传输"连接",但两者都失败了。

问题1.1

有谁知道 Signalr for .NET 的替代方案,它支持以不那么"我想拔头发"的方式使用负载平衡进行缩放?

SignalR 在 F5 后面带有 Redis 背板 - 状态代码:400,原因短语:“错误请求”

无需

配置源地址相关性即可在负载均衡器后面使用 SignalR。设置会话相关性当然没有错,但这并不能解决您的根本问题。

如果仔细查看 400 响应的内容,可能会看到类似于"ConnectionId 格式不正确"的消息。

SignalR

使用服务器的计算机密钥创建反 CSRF 令牌,但这要求服务器场中的所有服务器共享一个计算机密钥,以便在 SignalR 请求跃点服务器时正确解密令牌。您看到成功的/negotiate 请求是检索反 CSRF 令牌的请求。当 SignalR 客户端随后使用反 CSRF 令牌发出/connect 请求时,它会失败,因为/connect 请求由未创建令牌且无法解密的其他服务器处理。

这就解释了为什么设置会话相关性可以解决问题,但共享计算机密钥将有助于避免此问题,即使会话相关性出现问题也是如此。

这是遇到类似问题的人在 GitHub 上提出的问题:https://github.com/SignalR/SignalR/issues/2292。

通过在 F5 中将"MyApp"的配置文件切换为使用 F5 中内置的"source_addr"配置文件作为超时为 1 小时的父配置文件,修复了此问题。以下是该配置文件功能的说明:

源地址相关性持久性 也称为简单持久性, 源地址亲和持久性支持 TCP 和 UDP 协议, 并将会话请求定向到同一服务器仅基于 数据包的源 IP 地址。

编辑

这最终"工作"了一段时间,但是如果我部署发布者(仅通过 signalr 客户端发布的内容)而不重新发布 Hub,则发布者会超时尝试一遍又一遍地连接。 呃。