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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 13:45:26