首页 > 解决方案 > websocket握手期间的asp.net核心信号器错误

问题描述

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

来自客户端的代码:

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

我收到一个错误:错误:无法完成与服务器的协商:SyntaxError: Unexpected token < in JSON at position 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 时,我看不到它。我第一次拥有它。

我做错了什么?

启动.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");
        });
    }
}
}

标签: c#asp.net-corewebsocketsignalr

解决方案


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


推荐阅读