You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Blazor页面为何自动创建WebSocket连接?内置blazorpack连接疑问

关于Blazor内置WebSocket自动连接机制的解析与问题修复

一、Blazor自动建立WebSocket连接的原因

你看到的这个自动创建的WebSocket连接,是Blazor Server模式的核心通信通道——它基于SignalR实现,用来在服务器和客户端之间实时传输组件更新、用户交互事件等数据。

Blazor Server采用服务器托管架构:所有组件的逻辑计算都在后端服务器运行,前端浏览器只是负责渲染UI和转发用户操作。为了实现这种实时的双向通信,框架会自动启动一个WebSocket连接(优先选择,不可用时会降级为长轮询或Server-Sent Events),而{"protocol":"blazorpack","version":1}就是Blazor自定义的SignalR子协议,用来约定双方传输的数据格式。

二、解决自定义WebSocket与Blazor内置连接冲突的方案

你遇到的JSON解析异常,本质是因为Blazor的内置连接发送的消息格式和你的自定义WebSocket处理逻辑不兼容。这里有两种靠谱的解决思路:

1. 给自定义WebSocket指定独立路由

最推荐的方式是把你的自定义WebSocket服务和Blazor的内置连接分开到不同的路由端点。Blazor的SignalR连接默认使用/_blazor路由,你可以给你的服务配置一个专属路由(比如/ws-custom):

// 在Program.cs中配置中间件(ASP.NET Core 3.1对应Startup.cs的Configure方法)
app.UseWebSockets();

// 映射自定义WebSocket路由
app.Map("/ws-custom", subApp =>
{
    subApp.Use(async (context, next) =>
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            var webSocket = await context.WebSockets.AcceptWebSocketAsync();
            // 这里处理你的自定义WebSocket逻辑
            await HandleCustomWebSocketConnection(webSocket);
        }
        else
        {
            await next();
        }
    });
});

// 保留Blazor的默认配置
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

这样一来,Blazor的内置连接和你的自定义连接就不会在同一个端点上竞争,自然不会出现格式不匹配的问题。

2. 兼容Blazor的协议消息(不推荐)

如果必须在同一个端点处理所有WebSocket请求,你需要在消息处理逻辑中先判断是否是Blazor的blazorpack协议消息。如果是,可以选择忽略(因为这是Blazor自己的通信流量),或者按照SignalR的规范处理,但这种方式会增加代码复杂度,不建议采用。

三、修复JSON解析错误的细节

你日志里的Newtonsoft.Json.JsonReaderException,通常是因为WebSocket消息被拆分成了多个帧发送,你直接解析了不完整的字符串导致的。处理WebSocket消息时,要确保先拼接所有接收到的帧数据,得到完整的消息字符串后,再进行JSON反序列化。

举个简单的示例:

private async Task HandleCustomWebSocketConnection(WebSocket webSocket)
{
    var buffer = new byte[1024 * 4];
    WebSocketReceiveResult result;
    var messageBuilder = new StringBuilder();

    do
    {
        result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
        var messagePart = Encoding.UTF8.GetString(buffer, 0, result.Count);
        messageBuilder.Append(messagePart);

        // 只有当消息接收完成时才解析
        if (result.EndOfMessage)
        {
            var fullMessage = messageBuilder.ToString();
            messageBuilder.Clear();
            
            // 先判断是否是Blazor的协议消息,再处理自定义逻辑
            if (!fullMessage.Contains("blazorpack"))
            {
                try
                {
                    var data = JsonConvert.DeserializeObject<YourCustomModel>(fullMessage);
                    // 处理自定义消息
                }
                catch (JsonException ex)
                {
                    // 处理解析错误
                    Console.WriteLine($"解析消息失败: {ex.Message}");
                }
            }
        }
    } while (!result.CloseStatus.HasValue);

    await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}

内容的提问来源于stack exchange,提问作者Macindows

火山引擎 最新活动