Blazor Server端WebSocket 1006超时:如何延长适配长SQL查询?
解决Blazor Server中长SQL查询导致WebSocket 1006超时错误
核心问题分析
你遇到的1006错误是因为SignalR/WebSocket连接在长查询期间超时,仅设置CloseTimeout不足以覆盖所有超时控制点,需要同时配置SignalR的心跳机制、服务器请求超时以及SQL查询本身的超时阈值。
分步解决方案
1. 配置SignalR Hub的超时与心跳
Blazor Server依赖SignalR,除了CloseTimeout,还需设置ClientTimeoutInterval和KeepAliveInterval来维持连接存活:
// .NET 5及以前(Startup.cs的Configure方法) endpoints.MapBlazorHub(opts => { // 设置WebSocket关闭超时为5分钟 opts.WebSockets.CloseTimeout = TimeSpan.FromMinutes(5); // 服务器等待客户端响应的超时时间 opts.ClientTimeoutInterval = TimeSpan.FromMinutes(5); // 服务器发送心跳包的间隔,需短于ClientTimeoutInterval opts.KeepAliveInterval = TimeSpan.FromSeconds(10); }); // .NET 6+(Program.cs) app.MapBlazorHub(options => { options.WebSockets.CloseTimeout = TimeSpan.FromMinutes(5); options.ClientTimeoutInterval = TimeSpan.FromMinutes(5); options.KeepAliveInterval = TimeSpan.FromSeconds(10); });
KeepAliveInterval:定期发送心跳包,避免中间代理/防火墙因连接闲置断开连接ClientTimeoutInterval:服务器判定客户端断开的阈值,必须大于心跳间隔
2. 调整服务器请求超时
如果使用Kestrel作为服务器,需设置全局请求超时:
// .NET 6+(Program.cs) builder.WebHost.ConfigureKestrel(serverOptions => { // 设置请求超时为5分钟 serverOptions.Limits.RequestTimeout = TimeSpan.FromMinutes(5); }); // .NET 5及以前(Startup.cs的ConfigureServices) services.Configure<KestrelServerOptions>(options => { options.Limits.RequestTimeout = TimeSpan.FromMinutes(5); });
如果部署在IIS上,还需在web.config中添加IIS请求超时配置:
<system.webServer> <aspNetCore requestTimeout="00:05:00" /> </system.webServer>
3. 设置SQL查询超时
确保SQL查询本身不会先于连接超时,在DbContext或SqlCommand中设置命令超时:
// 使用EF Core时,在DbContext中设置 using var context = new YourDbContext(); // 设置命令超时为5分钟(300秒) context.Database.SetCommandTimeout(300); var reportData = await context.YourReportQuery.ToListAsync(); // 直接使用SqlCommand时 using var command = new SqlCommand("YourLongRunningQuery", connection); command.CommandTimeout = 300; var reader = await command.ExecuteReaderAsync();
4. 更优雅的方案:后台任务+SignalR推送
如果查询耗时极长(超过5分钟),建议将查询放到后台任务中执行,避免长时间占用SignalR连接,执行完成后通过SignalR主动推送结果给客户端:
步骤1:创建报表生成服务
public class ReportGeneratorService { private readonly IHubContext<BlazorHub> _hubContext; private readonly YourDbContext _dbContext; public ReportGeneratorService(IHubContext<BlazorHub> hubContext, YourDbContext dbContext) { _hubContext = hubContext; _dbContext = dbContext; } public async Task GenerateReportAsync(string userId) { // 设置SQL超时 _dbContext.Database.SetCommandTimeout(300); // 执行长查询 var reportData = await _dbContext.YourReportQuery.ToListAsync(); // 推送给指定用户 await _hubContext.Clients.User(userId).SendAsync("ReportGenerated", reportData); } }
步骤2:注册服务
// .NET 6+(Program.cs) builder.Services.AddScoped<ReportGeneratorService>(); // .NET 5及以前(Startup.cs) services.AddScoped<ReportGeneratorService>();
步骤3:在Blazor组件中订阅推送事件
@inject HubConnection HubConnection @inject ReportGeneratorService ReportService @code { private ReportData Report { get; set; } protected override async Task OnInitializedAsync() { // 订阅报表生成完成事件 await HubConnection.OnAsync("ReportGenerated", (ReportData data) => { Report = data; StateHasChanged(); return Task.CompletedTask; }); } // 触发报表生成 private async Task TriggerReportGeneration() { var userId = User.Identity.Name; await ReportService.GenerateReportAsync(userId); } }
验证要点
- 先测试前三个配置,确保所有超时时间都大于你的最长查询时长
- 如果部署在云服务器或有反向代理(如Nginx),需检查代理的超时设置(如Nginx的
proxy_read_timeout)
内容的提问来源于stack exchange,提问作者M-Corp
相关产品推荐
相关产品推荐

