websocket SignalR:服务器返回状态代码'200',而状态代码'101'是预期的

svujldwt  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(411)

我想通过signalR连接我的maui blazor应用程序(windows)到.net blazor服务器应用程序,这样我就可以将消息从服务器推送到客户端。我也用wpf dekstop app测试了一下,结果是一样的,握手失败。
我使用的版本:Microsoft.AspNetCore.SignalR.Client”Version=“6.0.1”,我尝试了7.0.1。
有趣的是,@localhost一切正常。而blazor wasm在同一台服务器上具有完整的信号R功能。
服务器端托管在@ akami
错误消息的详细信息:

Microsoft.AspNetCore.SignalR.Client.HubConnection: Trace: Waiting on Connection Lock in StartAsyncInner (/_/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs:247).
Microsoft.AspNetCore.SignalR.Client.HubConnection: Trace: The HubConnection is attempting to transition from the Disconnected state to the Connecting state.
Microsoft.AspNetCore.SignalR.Client.HubConnection: Debug: Starting HubConnection.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Starting HttpConnection.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Establishing connection with server at 'https://staging.vetat.work/hub/printertool'.
Microsoft.AspNetCore.Http.Connections.Client.Internal.LoggingHttpMessageHandler: Trace: Sending HTTP request POST 'https://staging.asd/hub/printertool/negotiate?negotiateVersion=1'.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Established connection 'B07mkUpGtdoEwG6C9uQZbA' with the server.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Starting transport 'WebSockets' with Url: https://staging.vetat.work/hub/printertool.
Microsoft.AspNetCore.Http.Connections.Client.Internal.WebSocketsTransport: Information: Starting transport. Transfer mode: Text. Url: 'wss://staging.vetat.work/hub/printertool?id=UGcgq9uJEOL5hZkA1iZxCQ'.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Error: Failed to start connection. Error starting transport 'WebSockets'.

System.Net.WebSockets.WebSocketException (0x80004005): The server returned status code '200' when status code '101' was expected.
   at System.Net.WebSockets.WebSocketHandle.ValidateResponse(HttpResponseMessage response, String secValue, ClientWebSocketOptions options)
   at System.Net.WebSockets.WebSocketHandle.ConnectAsync(Uri uri, HttpMessageInvoker invoker, CancellationToken cancellationToken, ClientWebSocketOptions options)
   at System.Net.WebSockets.ClientWebSocket.ConnectAsyncCore(Uri uri, HttpMessageInvoker invoker, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.Internal.WebSocketsTransport.DefaultWebSocketFactory(WebSocketConnectionContext context, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.Internal.WebSocketsTransport.StartAsync(Uri url, TransferFormat transferFormat, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.StartTransport(Uri connectUrl, HttpTransportType transportType, TransferFormat transferFormat, CancellationToken cancellationToken)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Skipping transport WebSockets because it failed to initialize.

System.Net.WebSockets.WebSocketException (0x80004005): The server returned status code '200' when status code '101' was expected.
   at System.Net.WebSockets.WebSocketHandle.ValidateResponse(HttpResponseMessage response, String secValue, ClientWebSocketOptions options)
   at System.Net.WebSockets.WebSocketHandle.ConnectAsync(Uri uri, HttpMessageInvoker invoker, CancellationToken cancellationToken, ClientWebSocketOptions options)
   at System.Net.WebSockets.ClientWebSocket.ConnectAsyncCore(Uri uri, HttpMessageInvoker invoker, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.Internal.WebSocketsTransport.DefaultWebSocketFactory(WebSocketConnectionContext context, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.Internal.WebSocketsTransport.StartAsync(Uri url, TransferFormat transferFormat, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.StartTransport(Uri connectUrl, HttpTransportType transportType, TransferFormat transferFormat, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.SelectAndStartTransport(TransferFormat transferFormat, CancellationToken cancellationToken)
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Establishing connection with server at 'https://staging.asd/hub/printertool'.
Microsoft.AspNetCore.Http.Connections.Client.Internal.LoggingHttpMessageHandler: Trace: Sending HTTP request POST 'https://staging.asd/hub/printertool/negotiate?negotiateVersion=1'.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Established connection 'trPpDN3vsUzTTUqSu0LdwQ' with the server.
Microsoft.AspNetCore.Http.Connections.Client.HttpConnection: Debug: Starting transport 'ServerSentEvents' with Url: https://staging.asd/hub/printertool.
Microsoft.AspNetCore.Http.Connections.Client.Internal.ServerSentEventsTransport: Information: Starting transport. Transfer mode: Text.
Microsoft.AspNetCore.Http.Connections.Client.Internal.LoggingHttpMessageHandler: Trace: Sending HTTP request GET 'https://staging.asd/hub/printertool?id=snz3w-l4JZ8sYDtO8cK9jQ'.

我试过maui应用程序,我试过调试,日志记录,wpf应用程序也。我希望我可以从服务器发送消息到客户端。

var url = _configuration[MauiConstants.AppConfig.SignalR];

        _connection = new HubConnectionBuilder()
            .WithUrl(url, options =>
            {
                options.AccessTokenProvider = () => Task.FromResult(token);
            })
            .ConfigureLogging(logging =>
            {
                // Log to the Console
                logging.AddDebug();

                // This will set ALL logging to Debug level
                logging.SetMinimumLevel(LogLevel.Trace);
            })
            .WithAutomaticReconnect()
            .Build();

对于授权,我使用不记名令牌
这是服务器配置:

if (config.SignalR.AllowCors)
    {
        _ = app.UseCors(builder =>
          {
              _ = builder.AllowAnyMethod()
                         .AllowAnyHeader()
                         .AllowCredentials()
                         .WithOrigins(config.SignalR.CorsAddress)
                         .SetIsOriginAllowedToAllowWildcardSubdomains();
          });
    }

_ = authenticationBuilder.AddJwtBearer(AuthConstant.Scheme.PrinterTool, options =>
    {
        options.RequireHttpsMetadata = false;
        options.SaveToken = true;
        options.Audience = $"{Audience.PrinterTool:G}";
        var signingKey = Convert.FromBase64String(secretKey);
        options.TokenValidationParameters = new TokenValidationParameters
        {
            AuthenticationType = AuthConstant.Scheme.PrinterTool,
            ValidateIssuer = false,
            ValidateAudience = true,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(signingKey),
            ClockSkew = TimeSpan.FromMinutes(Convert.ToDouble(config.AdminAppAuthentication.ExpiresIn))
        };

        options.Events = new JwtBearerEvents
        {
            OnAuthenticationFailed = context =>
            {
                if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                {
                    context.Response.Headers["Token-Expired"] = "true";
                }

                return Task.CompletedTask;
            },
            OnMessageReceived = context =>
            {
                //If the request is for our hub
                var path = context.HttpContext.Request.Path;

                if (path.StartsWithSegments(config.SignalR.PrinterToolMainHubRoute))
                {
                    var authorization = context.Request.Headers?.Authorization.FirstOrDefault(a => a.StartsWith("Bearer "));
                    if (!string.IsNullOrEmpty(authorization))
                    {
                        context.Token = authorization.Substring("Bearer ".Length);
                    }
                }

                return Task.CompletedTask;
            }
        };
    });
abithluo

abithluo1#

我想这个问题已经解决了。我也遇到了同样的问题,我解决了在prod服务器上更改nginx配置的问题
改变这一点:

proxy_set_header Connection keep-alive;

通过这个:

proxy_set_header Connection $http_connection;

完整的nginx配置:

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name api.your-domain.com;
    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;

    ssl_certificate /etc/nginx/ssl/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/live/your-domain.com/privkey.pem;

    location / {
        proxy_pass http://172.17.0.1:5000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $http_connection;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_headers_hash_max_size 512;
        proxy_headers_hash_bucket_size 128;
    }
}

来源:SignalR in ASP.NET Core behind Nginx

相关问题