ASP.NET Core SignalR 在 WebSocket 握手期间出错。

5

抱歉我的英语不好。我正在尝试从SPA应用程序(Vue.JS)连接到SignalR Hub。

客户端代码如下:

this.hubConnection = new HubConnectionBuilder()
    .withUrl('http://localhost:*****/testhub')
    .configureLogging(LogLevel.Information)
    .build()

我遇到了一个错误:错误:无法完成与服务器的协商:语法错误:JSON 中位置 0 处的 < 符号不符合预期 然后我尝试了:
this.hubConnection = new HubConnectionBuilder()
    .withUrl('http://localhost:*****/testhub', {
      skipNegotiation: true,
      transport: HttpTransportType.WebSockets
    })
    .configureLogging(LogLevel.Information)
    .build()

没有任何更改(但是我得到了另一个错误):

WebSocket连接到 'ws://localhost:50523/testhub' 失败:WebSocket握手期间出错:意外的响应代码:200

我在Startup.cs中检查了UseWebsockets。 我还尝试更改客户端中SignalR的版本,但无法解决问题。 当我尝试在多页面应用程序中连接SignalR时,我没有看到它。 我第一次拥有它。

我做错了什么?

Startup.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.SpaServices.Webpack;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.WebSockets;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Authorization;
using Newtonsoft.Json;
using Vue2Spa.Models;
using Vue2Spa.Controllers.App;
using Vue2Spa.Hubs;

namespace Vue2Spa
{
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddMvc().AddJsonOptions(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore)
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        var connection = @"Server=.\SQLEXPRESS;Database=****;Trusted_Connection=True;";
        services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connection));

        services.AddIdentity<Account, IdentityRole>(options =>
        options.SignIn.RequireConfirmedEmail = true)
        .AddDefaultTokenProviders()
        .AddEntityFrameworkStores<ApplicationDbContext>();

        //JWT
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata = false;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidIssuer = AuthOptions.ISSUER,
                    ValidateAudience = true,
                    ValidAudience = AuthOptions.AUDIENCE,
                    ValidateLifetime = true,
                    IssuerSigningKey = AuthOptions.GetSymmetricSecurityKey(),
                    ValidateIssuerSigningKey = true,
                };
            })


        services.AddAuthorization(options =>
        {

        });
        /*services.AddAuthorization(options =>
        {
            options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
                .RequireAuthenticatedUser()
                .Build();
        });*/

        // Simple example with dependency injection for a data provider.
        services.AddSingleton<Providers.IWeatherProvider, Providers.WeatherProviderFake>();

        //File's parameters
        services.Configure<FormOptions>(o => {
            o.ValueLengthLimit = int.MaxValue;
            o.MultipartBodyLengthLimit = int.MaxValue;
            o.MemoryBufferThreshold = int.MaxValue;
        });

        services.AddSignalR();

    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();

            // Webpack initialization with hot-reload.
            app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
            {
                HotModuleReplacement = true,
            });
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

            routes.MapRoute(
                name: "default1",
                template: "{controller=Admin}/{action=Index}/{id?}");

            routes.MapSpaFallbackRoute(
                name: "spa-fallback",
                defaults: new { controller = "Home", action = "Index" });

            routes.MapSpaFallbackRoute(
                name: "spa-fallback1",
                defaults: new { controller = "Admin", action = "Index" });
        });
        app.UseAuthentication();
        app.Use(async (context, next) =>
        {
            context.Response.Headers.Add("X-Xss-Protection", "1");
            await next();
        }).UseSignalR(route =>
        {
            route.MapHub<ChatHub>("/chat");
        });
    }
}
}

他似乎通过将调用app.UseSignalR()移动到app.UseMvc()之上来解决了问题,这似乎很奇怪。在你的Startup.cs中,你是如何配置它的?你必须调用services.AddSignalR();app.UseSignalR(routes =>...,也许可以与我们分享一下你代码中的这部分内容。 - jpgrassi
我也移动了它,但它无法解决这个问题。 - General2001
你能否创建一个样例应用程序来重现这个问题? - jpgrassi
没有,但我有另一个项目,我创建了一种替代应用程序。但它有很多页面。 - General2001
尝试将 UseSignalR(route => 移动到 UseMvc 之上,放在 Configure 中。 - jpgrassi
显示剩余4条评论
2个回答

9
问题已解决。我将 UseSignalR 移到 UseMvc 之上。

2
当UseSignalR在UseMvc之上时,我遇到了相同的问题。 - Vlad Kiselev
该死,这么简单的问题解决了几个小时的调试... :-) - mtholen

4
在 .NET Core 3 中,您可以这样做:
services.AddSignalR();

app.UseEndpoints( endpoints => {
    endpoints.MapControllers();
    endpoints.MapHub<ChatHub>( "/chatHub" );
} );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接