You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

本地测试Azure App Service上的SignalR时WebSocket握手返回200错误

SignalR连接Azure App Service失败排查与解决

问题描述

本地测试部署在Azure App Service的SignalR聊天应用时,遇到两类连接错误:

  1. 开启skipNegotiation: true时:

    WebSocket connection to 'wss:.azurewebsites.net/Chat' failed: Error during WebSocket handshake: Unexpected response code: 200
    后端日志:Exception: The underlying connection was closed before the hub handshake could complete.

  2. 关闭skipNegotiation(设为false)时:

    connection to signalr Unexpected end of JSON input

环境配置

  • 后端:.NET 8 + SignalR
  • 前端:Flutter + signalr_core库
  • 托管:Azure App Service
  • 后端配置:已注册SignalR、映射/Chat Hub、启用全量CORS策略、配置QueryStringUserIdProvider
  • 前端配置:signalr_core指定WebSocket传输、手动设置协商开关

一、Azure App Service关键配置检查

  • 开启WebSockets支持:
    进入Azure门户的App Service → 配置 → 常规设置,找到Web sockets选项,设置为开启,保存后重启应用。Azure默认关闭WebSocket,这是导致握手失败返回200的核心原因。
  • SignalR服务扩展检查(可选):
    若使用Azure SignalR Service(而非自托管SignalR),需在App Service的配置中添加AzureSignalRConnectionString应用设置,同时后端安装Microsoft.Azure.SignalR包,修改注册代码为builder.Services.AddSignalR().AddAzureSignalR();。自托管SignalR可跳过此步,但必须确保WebSocket已开启。

二、后端代码调整

  1. 修正CORS与中间件配置:
    SignalR依赖凭证支持,需在CORS策略中添加AllowCredentials(),同时确保中间件顺序正确:
    // Program.cs
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddSignalR();
    builder.Services.AddCors(options =>
    {
        options.AddPolicy("CorsPolicy", policy =>
        {
            policy.AllowAnyOrigin()
                  .AllowAnyHeader()
                  .AllowAnyMethod()
                  .AllowCredentials(); // 必须添加,SignalR握手依赖此配置
        });
    });
    var app = builder.Build();
    
    app.UseCors("CorsPolicy"); // 确保CORS在路由之前执行
    app.UseRouting();
    app.MapHub<ChatHub>("/Chat");
    app.Run();
    
  2. 验证Hub类实现:
    确保ChatHub继承自Hub,无自定义握手拦截逻辑:
    public class ChatHub : Hub
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }
    }
    

三、Flutter前端代码修正

  1. 跳过协商模式(skipNegotiation: true):
    跳过协商时,需直接访问SignalR的WebSocket专用端点,路径需追加/ws:
    // chat_hub_service.dart
    _connection = HubConnectionBuilder()
        .withUrl('wss://<your-app>.azurewebsites.net/Chat/ws',
            HttpConnectionOptions(
              skipNegotiation: true,
              transport: HttpTransportType.webSockets,
            ))
        .build();
    await _connection.start();
    
  2. 协商模式(推荐,skipNegotiation: false):
    移除手动指定的传输方式,用https://开头的URL,客户端会自动协商最佳传输:
    // chat_hub_service.dart
    _connection = HubConnectionBuilder()
        .withUrl('https://<your-app>.azurewebsites.net/Chat')
        .build();
    await _connection.start();
    

四、额外排查步骤

  • 先测试本地后端连接:用Flutter客户端连接ws://localhost:<port>/Chat/ws(跳过协商)或http://localhost:<port>/Chat(协商模式),确认代码逻辑无问题。
  • 查看Azure应用日志:进入App Service → 日志 → 应用日志,检查是否有CORS拦截、路由匹配失败等详细错误。
  • 排除代理/防火墙干扰:本地测试时确保没有代理或防火墙拦截443端口的wss://流量。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 14:17:09