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,提问作者محمد حسین مهتری
相关产品推荐
相关产品推荐

