如何在Blazor中处理ASP.NET Core 10.0服务器发送事件(SSE)?
如何在Blazor中处理ASP.NET Core 10.0服务器发送事件(SSE)?
ASP.NET Core 10.0刚发布的时候,我就发现它新增了对服务器发送事件(SSE)的支持,刚好项目里需要实时推送数据,就折腾出了一套可行的方案——先是参考了官方示例,又结合了一个开源仓库的实现思路调整了细节。
我先把后端的SSE接口搭起来,用MinAPI写起来超简单,比如:
app.MapGet("/sse", async (HttpContext context) => { // 配置SSE必须的响应头 context.Response.Headers.Append("Content-Type", "text/event-stream"); context.Response.Headers.Append("Cache-Control", "no-cache"); context.Response.Headers.Append("Connection", "keep-alive"); var counter = 0; // 持续推送消息直到连接被主动取消 while (!context.RequestAborted.IsCancellationRequested) { await context.Response.WriteAsync($"data: 实时推送消息 {++counter}\n\n"); await context.Response.Body.FlushAsync(); await Task.Delay(1000, context.RequestAborted); } });
写完后端我先用curl测了下,执行curl http://localhost:5000/sse,确实能每隔一秒收到一条消息,说明后端的SSE服务是正常工作的。
接下来就是Blazor前端的处理了,因为Blazor本身没有原生的SSE客户端封装,所以得借助JavaScript互操作来实现:
第一步:在Blazor组件里添加SSE逻辑
我在组件里实现了IAsyncDisposable接口,用来在组件销毁时关闭SSE连接,避免内存泄漏:
@implements IAsyncDisposable @inject IJSRuntime JS <p>最新消息:@latestMessage</p> @code { private string latestMessage = "等待推送..."; private IJSObjectReference? sseUtilModule; protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { // 导入JS模块 sseUtilModule = await JS.InvokeAsync<IJSObjectReference>("import", "./js/sse-utils.js"); // 初始化SSE连接 await sseUtilModule.InvokeVoidAsync("setupSSE", "/sse", (Action<string>)HandleNewMessage); } await base.OnAfterRenderAsync(firstRender); } private void HandleNewMessage(string message) { latestMessage = message; // 通知组件更新UI StateHasChanged(); } public async ValueTask DisposeAsync() { if (sseUtilModule is not null) { // 关闭SSE连接 await sseUtilModule.InvokeVoidAsync("closeSSE"); await sseUtilModule.DisposeAsync(); } } }
第二步:编写JS工具文件
在wwwroot/js目录下创建sse-utils.js,封装SSE的核心操作:
let eventSourceInstance; export function setupSSE(url, messageCallback) { // 创建SSE连接实例 eventSourceInstance = new EventSource(url); // 监听服务器推送的消息 eventSourceInstance.onmessage = (event) => { messageCallback(event.data); }; // 处理连接异常 eventSourceInstance.onerror = (error) => { console.error("SSE连接出错:", error); closeSSE(); }; } export function closeSSE() { if (eventSourceInstance) { eventSourceInstance.close(); eventSourceInstance = null; } }
几个要注意的细节
- 后端必须正确设置SSE的响应头,不然浏览器不会把响应识别为SSE流
- 如果是Blazor WebAssembly项目,要记得在后端配置CORS,允许前端域名访问SSE接口
- 一定要在组件销毁时关闭SSE连接,不然会造成不必要的资源浪费
内容来源于stack exchange
相关产品推荐
相关产品推荐

