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

ASP.NET Core 6无需Timer、SignalR和Ajax实现后端向前端推送请求求助

基于ASP.NET Core 6的后端前端推送方案(避开SignalR/Timer/Ajax)

方案1:Server-Sent Events (SSE)

SSE是HTTP原生的单向推送机制,轻量无额外依赖,完全适配后端主动向前端推送数据的需求,无需前端轮询。

后端实现

创建API控制器维护消息队列,按需推送数据:

[ApiController]
[Route("api/[controller]")]
public class PushController : ControllerBase
{
    private static readonly ConcurrentQueue<string> _messageQueue = new();
    private static readonly CancellationTokenSource _cts = new();

    // 供业务逻辑调用,添加待推送消息
    public static void EnqueueMessage(string message)
    {
        _messageQueue.Enqueue(message);
    }

    [HttpGet("stream")]
    public async Task StreamUpdates(CancellationToken cancellationToken)
    {
        Response.Headers.Add("Content-Type", "text/event-stream");
        Response.Headers.Add("Cache-Control", "no-cache");
        Response.Headers.Add("Connection", "keep-alive");

        var linkedToken = CancellationTokenSource
            .CreateLinkedTokenSource(_cts.Token, cancellationToken)
            .Token;

        try
        {
            while (!linkedToken.IsCancellationRequested)
            {
                if (_messageQueue.TryDequeue(out var message))
                {
                    await Response.WriteAsync($"data: {JsonSerializer.Serialize(message)}\n\n", linkedToken);
                    await Response.Body.FlushAsync(linkedToken);
                }
                else
                {
                    // 无消息时短暂休眠,避免空循环占用CPU
                    await Task.Delay(100, linkedToken);
                }
            }
        }
        catch (OperationCanceledException)
        {
            // 连接正常关闭,无需额外处理
        }
    }
}

业务逻辑中需要推送时,直接调用PushController.EnqueueMessage("推送内容")即可。

前端实现

使用原生EventSource接收推送:

const eventSource = new EventSource('/api/push/stream');

eventSource.onmessage = (event) => {
    const payload = JSON.parse(event.data);
    console.log('收到推送:', payload);
    // 这里更新页面内容或执行业务逻辑
};

eventSource.onerror = (error) => {
    console.error('SSE连接异常:', error);
    eventSource.close();
    // 可选:5秒后尝试重连
    setTimeout(() => {
        // 重新初始化EventSource
    }, 5000);
};

方案2:原生WebSocket

如果需要更灵活的双向通信能力(也支持单向推送),原生WebSocket比SignalR更轻量,能避免SignalR封装带来的性能开销。

后端实现

在Program.cs中配置WebSocket中间件:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseWebSockets();

app.Map("/ws", async context => {
    if (!context.WebSockets.IsWebSocketRequest)
    {
        context.Response.StatusCode = StatusCodes.Status400BadRequest;
        return;
    }

    using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
    var buffer = new byte[1024 * 4];

    try
    {
        while (webSocket.State == WebSocketState.Open)
        {
            // 从业务逻辑获取待推送消息(示例中模拟生成消息)
            var message = $"推送内容:{DateTime.Now:yyyy-MM-dd HH:mm:ss}";
            var messageBytes = Encoding.UTF8.GetBytes(message);
            
            await webSocket.SendAsync(
                new ArraySegment<byte>(messageBytes),
                WebSocketMessageType.Text,
                endOfMessage: true,
                CancellationToken.None);
            
            await Task.Delay(1000);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"WebSocket错误:{ex.Message}");
    }
});

app.Run();

前端实现

const socket = new WebSocket('ws://localhost:5000/ws');

socket.onopen = () => console.log('WebSocket连接已建立');

socket.onmessage = (event) => {
    console.log('收到推送:', event.data);
    // 处理业务逻辑
};

socket.onerror = (error) => console.error('WebSocket异常:', error);

socket.onclose = () => console.log('WebSocket连接已关闭');

性能优化要点

  • 对SSE连接,在前端断开时后端要及时释放资源,避免无效连接占用内存。
  • 消息队列使用线程安全容器(如ConcurrentQueue),防止多线程读写冲突。
  • 推送逻辑仅负责发送数据,耗时的业务处理要放在单独线程或任务中,避免阻塞推送线程。

内容的提问来源于stack exchange,提问作者محمد حسین مهتری

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:10:50