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

单元测试环境下WebSocket连接失败返回404错误问题排查

问题原因
  • 核心错误:中间件注册顺序不符合ASP.NET Core管道规则
    ASP.NET Core请求管道严格按代码书写顺序执行,前序中间件生成响应后,后续中间件不会再处理请求。你当前RunAppAsync方法中,先注册了所有HTTP接口端点(MapGet、业务用例端点、控制器),最后才调用app.UseWebSockets()注册WebSocket中间件。WebSocket升级请求到达后,先被端点路由层处理,因未经过协议升级无法匹配到对应处理逻辑,直接返回404,位于管道末尾的WebSocket中间件根本接触不到请求。
  • 测试启动逻辑存在缺陷
    你在测试静态构造函数中用_ = Program.RunAppAsync(app)直接丢弃异步启动任务,既不捕获启动异常,也不等待应用完成全量初始化,虽然简单GET请求可能碰巧访问成功,但WebSocket相关端点可能未完成注册就收到请求,也会触发异常。
修复方案
  1. 调整中间件注册顺序,将WebSocket中间件移到所有端点注册逻辑之前
public static async Task RunAppAsync(WebApplication app)
{
    // WebSocket中间件必须放在所有路由、端点配置之前
    app.UseWebSockets();
    app.MapGet("/", () => "Gambit.Server.API is running");
    app.AddUserUseCases();
    app.AddGameUseCases();
    app.MapControllers();
    await app.RunAsync();
}
  1. 优化测试服务启动逻辑,等待应用完全启动后再执行测试用例
static async Task<WebApplication> StartTestServer()
{
    ConfigureMocks();
    Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "IntegrationTesting");
    var app = Program.BuildApp(Array.Empty<string>(), builder =>
    {
        builder.WebHost.UseSetting("urls", "https://localhost:8080");
    });

    // 初始化数据库
    Configuration = app.Services.GetRequiredService<IConfiguration>();
    GameServerOptions = app.Services.GetRequiredService<IOptions<GameServerOptions>>();
    var dbContextOptions = app.Services.GetRequiredService<DbContextOptions<ApplicationDbContext>>();
    using var dbContext = new ApplicationDbContext(dbContextOptions);
    dbContext.Database.EnsureDeleted();
    dbContext.Database.EnsureCreated();

    // 启动服务并等待初始化完成
    var runTask = Program.RunAppAsync(app);
    var lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
    var startWaiter = new TaskCompletionSource();
    lifetime.ApplicationStarted.Register(() => startWaiter.SetResult());
    // 设置10秒启动超时,避免无限等待
    await startWaiter.Task.WaitAsync(TimeSpan.FromSeconds(10));

    HttpClient = new HttpClient { BaseAddress = new Uri("https://localhost:8080") };
    return app;
}

测试初始化时异步调用该方法等待服务启动完成,测试执行结束后调用app.StopAsync()释放端口资源即可。

调整后WebSocket升级请求会先经过WebSocket中间件完成协议升级,再匹配到/game-server端点返回101切换协议响应,404问题会完全消失。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 02:18:03